有没有一种方法可以通过SAX/DOM解析每个节点可用的行号
问题描述:
我已经为包含大量可用于自动生成Java代码的项目的大型XML文档格式编写了DOM解析器。这仅限于小型表达式,然后将其合并到动态生成的Java源文件中。有没有一种方法可以通过SAX/DOM解析每个节点可用的行号
到目前为止 - 太好了。一切正常。
但我希望能够嵌入包含Java代码的XML节点的行号(这样如果配置包含不可编译的代码,每个方法都会有一个指向源XML文档的指针和线号以方便调试)。我不需要解析时的行号,也不需要验证XML源文档并在特定的行号处发生错误。我需要能够访问我的DOM中的每个节点和属性的行号或每个SAX事件。
关于我如何能够实现这一点的任何建议?
P.S. 此外,我读StAX有一个方法来解析时获取行号,但理想情况下,我希望在Java 4/5中使用常规SAX/DOM处理实现相同的结果,而不是成为Java 6+应用程序或采取额外.jar文件。
答
我知道这个线程是有点老了(对不起),但它已经采取了这么长时间才破解这个螺母,我不得不与别人分享的解决方案...
你只能似乎能够获得没有构建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);
}
}
太好了,我会检查出来。我问了这个问题,因为我似乎已经消耗了一些错误信息,声称在1.4/5.0的默认SAX处理器中这是不可能的。如果我有成功,我会在这里报告。 – Chris 2010-05-09 17:52:20
谢谢,正是我在寻找的。 – jutky 2011-11-02 11:39:51