Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looping over nodes and extracting specific subnode values using Java's XPath

Tags:

java

xpath

I understand from Googling that it makes more sense to extract data from XML using XPath than by using DOM looping.

At the moment, I have implemented a solution using DOM, but the code is verbose, and it feels untidy and unmaintainable, so I would like to switch to a cleaner XPath solution.

Let's say I have this structure:

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

I want to be able to run a for loop for each of the <product> elements, and inside this for loop, extract the title and image node values.

My code looks like this:

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

Inside my for loop I get each <product> as a Node, which is cast to an Element.

Can I simply use my instance of XPathExpression to compile and run another XPath on the Node or the Element?

like image 306
BoomShaka Avatar asked Oct 22 '10 11:10

BoomShaka


1 Answers

Yes, you can always do like this -

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

Here I have given example of extracting the 'title' value. In same way you can do for 'image'

like image 77
Gopi Avatar answered Oct 16 '22 01:10

Gopi