有没有办法通过SAX/DOM解析XML,每个节点可用行号

Chr*_*ris 5 java xml dom sax

我已经为大型XML文档格式编写了一个DOM解析器,其中包含许多可用于自动生成Java代码的项目.这仅限于小表达式,然后合并到动态生成的Java源文件中.

到现在为止还挺好.一切正常.

但是 - 我希望能够嵌入包含Java代码的XML节点的行号(这样如果配置包含不可编译的代码,每个方法都会有一个指向源XML文档和行号的指针以方便调试).我在分析时不需要行号,我不需要验证XML源文档并在特定的行号处抛出错误.我需要能够访问我的DOM或每个SAX事件中的每个节点和属性的行号.

关于我如何能够实现这一目标的任何建议?

PS另外,我读到StAX有一种在解析时获取行号的方法,但理想情况下我希望在Java 4/5中使用常规SAX/DOM处理获得相同的结果,而不是成为Java 6+应用程序或承担额外的.jar文件.

小智 8

我知道这个帖子有点旧(对不起),但是我花了这么长时间才解决这个问题我不得不与某人分享解决方案......

您似乎只能使用不构建DOM的SAX获取行号.DOM解析器不提供行号,也不会让您靠近它正在使用的SAX解析器.我的解决方案是使用SAX源和DOM结果进行空XSLT转换,但即使这样,有人也尽力隐藏它.请参阅下面的代码.

我将位置信息作为具有我自己的命名空间的属性添加到每个元素,因此我可以使用XPath查找元素并报告数据的来源.

希望这可以帮助:

// The file to parse.
String systemId = "myxml.xml";

/*
 * Create transformer SAX source that adds current element position to
 * the element as attributes.
 */
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
LocationFilter locationFilter = new LocationFilter(xmlReader);

InputSource inputSource = new InputSource(new FileReader(systemId));
// Do this so that XPath function document() can take relative URI.
inputSource.setSystemId(systemId);
SAXSource saxSource = new SAXSource(locationFilter, inputSource);

/*
 * Perform an empty transformation from SAX source to DOM result.
 */
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMResult domResult = new DOMResult();
transformer.transform(saxSource, domResult);
Node root = domResult.getNode();

...
class LocationFilter extends XMLFilterImpl {

    LocationFilter(XMLReader xmlReader) {
        super(xmlReader);
    }

    private Locator locator = null;

    @Override
    public void setDocumentLocator(Locator locator) {
        super.setDocumentLocator(locator);
        this.locator = locator;
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

        // Add extra attribute to elements to hold location
        String location = locator.getSystemId() + ':' + locator.getLineNumber() + ':' + locator.getColumnNumber();
        Attributes2Impl attrs = new Attributes2Impl(attributes);
        attrs.addAttribute("http://myNamespace", "location", "myns:location", "CDATA", location);
        super.startElement(uri, localName, qName, attrs);
    }
}
Run Code Online (Sandbox Code Playgroud)