从xml节点获取行号 – java

我已经解析了一个XML文件,并且得到了一个我感兴趣的节点。我现在如何在源XML文件中找到此节点出现的行号?

编辑:目前我正在使用SAXParser来解析我的XML。 但是我会对使用任何解析器的解决方案感到满意。

与Node一起,我也有节点的XPath表达式。

我需要获取行号,因为我在文本框中显示XML文件,并需要突出显示节点发生的行。 假设XML文件的格式很好,并且有足够的换行符。

按照这个例子,我有这个工作:

http://eyalsch.wordpress.com/2010/11/30/xml-dom-2/

该解决方案遵循Michael Kay建议的方法。 以下是您使用它的方式:

// XmlTest.java import java.io.ByteArrayInputStream; import java.io.InputStream; import org.w3c.dom.Document; import org.w3c.dom.Node; public class XmlTest { public static void main(final String[] args) throws Exception { String xmlString = "\n" + " \n" + " Hello World!\n" + " \n" + ""; InputStream is = new ByteArrayInputStream(xmlString.getBytes()); Document doc = PositionalXMLReader.readXML(is); is.close(); Node node = doc.getElementsByTagName("moo").item(0); System.out.println("Line number: " + node.getUserData("lineNumber")); } } 

如果您运行此程序,它将输出:“行号:3”

PositionalXMLReader是上面链接的示例的略微修改版本。

 // PositionalXMLReader.java import java.io.IOException; import java.io.InputStream; import java.util.Stack; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class PositionalXMLReader { final static String LINE_NUMBER_KEY_NAME = "lineNumber"; public static Document readXML(final InputStream is) throws IOException, SAXException { final Document doc; SAXParser parser; try { final SAXParserFactory factory = SAXParserFactory.newInstance(); parser = factory.newSAXParser(); final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); final DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); doc = docBuilder.newDocument(); } catch (final ParserConfigurationException e) { throw new RuntimeException("Can't create SAX parser / DOM builder.", e); } final Stack elementStack = new Stack(); final StringBuilder textBuffer = new StringBuilder(); final DefaultHandler handler = new DefaultHandler() { private Locator locator; @Override public void setDocumentLocator(final Locator locator) { this.locator = locator; // Save the locator, so that it can be used later for line tracking when traversing nodes. } @Override public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException { addTextIfNeeded(); final Element el = doc.createElement(qName); for (int i = 0; i < attributes.getLength(); i++) { el.setAttribute(attributes.getQName(i), attributes.getValue(i)); } el.setUserData(LINE_NUMBER_KEY_NAME, String.valueOf(this.locator.getLineNumber()), null); elementStack.push(el); } @Override public void endElement(final String uri, final String localName, final String qName) { addTextIfNeeded(); final Element closedEl = elementStack.pop(); if (elementStack.isEmpty()) { // Is this the root element? doc.appendChild(closedEl); } else { final Element parentEl = elementStack.peek(); parentEl.appendChild(closedEl); } } @Override public void characters(final char ch[], final int start, final int length) throws SAXException { textBuffer.append(ch, start, length); } // Outputs text accumulated under the current node private void addTextIfNeeded() { if (textBuffer.length() > 0) { final Element el = elementStack.peek(); final Node textNode = doc.createTextNode(textBuffer.toString()); el.appendChild(textNode); textBuffer.delete(0, textBuffer.length()); } } }; parser.parse(is, handler); return doc; } } 

如果您使用的是SAX解析器,则可以使用Locator对象获取事件的行号,该对象通过setDocumentLocator()回调通知ContentHandler。 这在解析开始时调用,您需要保存定位器; 然后在任何事件(例如startElement())之后,可以调用getLineNumber()等方法来获取源文件中的当前位置。 (在startElement()之后,定义回调以提供出现开始标记的“>”的行号。)

请注意,根据规范( Locator.getLineNumber() ),该方法返回SAX事件结束的行号!

在“startElement()”的情况下,这意味着:

这里Element的行号是1

  

这里Element的行号是3