2010-10-22 12 views
5

Entiendo por Google que tiene más sentido extraer datos de XML utilizando XPath que utilizando el bucle DOM.Looping sobre nodos y extracción de valores de subnodos específicos utilizando XPath de Java

Por el momento, he implementado una solución usando DOM, pero el código es detallado, y se siente desordenado y no se puede mantener, así que me gustaría cambiar a una solución XPath más limpia.

Digamos que tengo esta estructura:

<products> 
    <product> 
     <title>Some title 1</title> 
     <image>Some image 1</image> 
    </product> 
    <product> 
     <title>Some title 2</title> 
     <image>Some image 2</image> 
    </product> 
    ... 
</products> 

Quiero ser capaz de ejecutar un bucle para cada uno de los <product> elementos, y dentro de este bucle, extraer los valores de los nodos de título y de imagen.

Mi código es el siguiente:

InputStream is = conn.getInputStream();   
DocumentBuilder builder = 
    DocumentBuilderFactory.newInstance().newDocumentBuilder(); 
Document doc = builder.parse(is); 
XPathFactory factory = XPathFactory.newInstance(); 
XPath xpath = factory.newXPath(); 
XPathExpression expr = xpath.compile("/products/product"); 
Object result = expr.evaluate(doc, XPathConstants.NODESET); 
NodeList products = (NodeList) result; 
for (int i = 0; i < products.getLength(); i++) { 
    Node n = products.item(i); 
    if (n != null && n.getNodeType() == Node.ELEMENT_NODE) { 
     Element product = (Element) n; 
     // do some DOM navigation to get the title and image 
    } 
} 

Dentro de mi bucle for me sale cada <product> como Node, que se convierte en una Element.

¿Puedo simplemente usar mi instancia de XPathExpression para compilar y ejecutar otro XPath en el Node o la Element?

Respuesta

6

Sí, puede hacerlo siempre así -

XPathFactory factory = XPathFactory.newInstance(); 
XPath xpath = factory.newXPath(); 
XPathExpression expr = xpath.compile("/products/product"); 
Object result = expr.evaluate(doc, XPathConstants.NODESET); 
expr = xpath.compile("title"); // The new xpath expression to find 'title' within 'product'. 

NodeList products = (NodeList) result; 
for (int i = 0; i < products.getLength(); i++) { 
    Node n = products.item(i); 
    if (n != null && n.getNodeType() == Node.ELEMENT_NODE) { 
     Element product = (Element) n; 
     NodeList nodes = (NodeList) expr.evaluate(product,XPathConstants.NODESET); //Find the 'title' in the 'product' 
     System.out.println("TITLE: " + nodes.item(0).getTextContent()); // And here is the title 
    } 
}  

Aquí me han dado ejemplo de extraer el valor 'título'. De la misma forma que puede hacerlo para 'imagen'

4

No soy un gran admirador de este enfoque porque debe compilar un documento (que puede ser costoso) antes de poder aplicar XPaths.

que he encontrado VTD-XML mucho más eficiente cuando se trata de aplicar XPaths a los documentos, ya que no tiene que cargar todo el documento en la memoria. Aquí hay un código de ejemplo:

final VTDGen vg = new VTDGen(); 
vg.parseFile("file.xml", false); 
final VTDNav vn = vg.getNav(); 
final AutoPilot ap = new AutoPilot(vn); 

ap.selectXPath("/products/product"); 
while (ap.evalXPath() != -1) { 
    System.out.println("PRODUCT:"); 

    // you could either apply another xpath or simply get the first child 
    if (vn.toElement(VTDNav.FIRST_CHILD, "title")) { 
     int val = vn.getText(); 
     if (val != -1) { 
      System.out.println("Title: " + vn.toNormalizedString(val)); 
     } 
     vn.toElement(VTDNav.PARENT); 
    } 
    if (vn.toElement(VTDNav.FIRST_CHILD, "image")) { 
     int val = vn.getText(); 
     if (val != -1) { 
      System.out.println("Image: " + vn.toNormalizedString(val)); 
     } 
     vn.toElement(VTDNav.PARENT); 
    } 
} 

también ver este mensaje el Faster XPaths with VTD-XML.

Cuestiones relacionadas