我已经解析了一个XML文件,并获得了一个我感兴趣的Node,现在我如何找到源节点发生的源XML文件中的行号?
编辑:
目前我正在使用SAXParser解析我的XML。然而,我将对使用任何解析器的解决方案感到满意。
与节点一起,我也有节点的XPath表达式。
按照这个例子我已经得到了这个工作:
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 = "<foo>\n" + " <bar>\n" + " <moo>Hello World!</moo>\n" + " </bar>\n" + "</foo>"; 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<Element> elementStack = new Stack<Element>(); 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 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; } }