2010-10-22 9 views
5

Capisco da Google che ha più senso estrarre dati da XML utilizzando XPath piuttosto che utilizzando il ciclo DOM.Loop su nodi ed estrazione di valori di nodo secondario utilizzando XPath di Java

Al momento, ho implementato una soluzione utilizzando DOM, ma il codice è dettagliato e risulta disordinato e non gestibile, quindi mi piacerebbe passare a una soluzione XPath più pulita.

Diciamo ho questa struttura:

<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> 

Voglio essere in grado di eseguire un ciclo for per ciascuno degli <product> elementi, e all'interno di questo ciclo for, estrarre i valori dei nodi titolo e immagine.

Il mio codice è simile al seguente:

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 il mio for ciclo ricevo ogni <product> come Node, che viene gettato a un Element.

Posso semplicemente usare la mia istanza di XPathExpression per compilare ed eseguire un altro XPath sul Node o Element?

risposta

6

Sì, si può sempre fare come questo -

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

Qui mi hanno dato esempio di estrarre il valore 'titolo'. Nello stesso modo si può fare per 'image'

4

Non sono un grande fan di questo approccio perché devi creare un documento (che potrebbe essere costoso) prima di poter applicare XPath ad esso.

Ho trovato VTD-XML molto più efficiente quando si tratta di applicare XPath ai documenti, perché non è necessario caricare l'intero documento in memoria. Ecco alcuni esempi di codice:

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

vedere anche questo post su Faster XPaths with VTD-XML.

Problemi correlati