Obtener el número de línea del nodo xml – java

He analizado un archivo XML y he obtenido un Nodo que me interesa. ¿Cómo puedo encontrar ahora el número de línea en el archivo XML de origen donde se encuentra este nodo?

EDITAR: Actualmente estoy usando SAXParser para analizar mi XML. Sin embargo, estaré contento con una solución que use cualquier analizador.

Junto con el nodo, también tengo la expresión XPath para el nodo.

Necesito obtener el número de línea porque estoy mostrando el archivo XML en un cuadro de texto, y necesito resaltar la línea donde ocurrió el nodo. Supongamos que el archivo XML está muy bien formateado con suficientes saltos de línea.

Lo he conseguido siguiendo este ejemplo:

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

Esta solución sigue el método sugerido por Michael Kay. Aquí es cómo lo usa:

// 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")); } } 

Si ejecuta este progtwig, saldrá: “Número de línea: 3”

PositionalXMLReader es una versión ligeramente modificada del ejemplo vinculado anteriormente.

 // 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; } } 

Si está utilizando un analizador SAX, entonces se puede obtener el número de línea de un evento utilizando el objeto Locator, que se notifica al ContentHandler a través de la callback setDocumentLocator (). Esto se llama al inicio del análisis, y debe guardar el Localizador; luego, después de cualquier evento (como startElement ()), puede llamar a métodos como getLineNumber () para obtener la posición actual en el archivo fuente. (Después de startElement (), la callback se define para darle el número de línea en el que aparece el “>” de la etiqueta de inicio).

Tenga en cuenta que según la especificación (de Locator.getLineNumber () ) el método devuelve el número de línea donde termina el evento SAX.

En el caso de “startElement ()” esto significa:

Aquí el número de línea para Element es 1 :

  

Aquí el número de línea para Element es 3 :