How to use XPath to filter elements by TextContent? get parent by axis?

13,554

Solution 1

If I wanna get a "filtered" subset of the item elements from this XML, how could I use an XPath expression to directly address that?

An example XPath expression:

/*/item[id/@isInStock='true']/category/text()

This XPath expression selects all text-node children of all <category> elements of all <item> elements the isInStock attribute of whose id child has a value of 'true' and (the id elements) that are children of the top element of the XML document.

Another question is : how could I refer to the parent node properly?

Use:

parent::node()

or simply

..

Solution 2

Java.

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Node;

Following XPath expression can be used to filter element by text contents.

**String xPathString = "/root/item/category[text()='Bouquet Balloon']";** 

XPath xPath = XPathFactory.newInstance().newXPath();     
XPathExpression xPathExpression = xPath.compile(xPathString);

Get the result evaluated to the a required type,

Object result = xPathExpression.evaluate(getDrugBankXMLDoc(), XPathConstants.NODE);

Get the parent of the selected Node (import org.w3c.dom.Node;),

Node baloon = (Node)result;
if (baloon != null)
{
     baloon = baloon.getParentNode();
}

Solution 3

To select the item, You can continue the path after the predicate to jump back to the parent of the found id(s)

XPathExpression expr = xpath.compile("/root/item/id[@isInStock='true']/../text()");

When you evaluate this, it should return a NodeList containing the filtered item Nodes (and their subtrees), which you can then iterate through.

Share:
13,554
Michael Mao
Author by

Michael Mao

Hi all. I now work at IBM as Associative Support Software Engineer in Sydney. I am always interested in developing my programming skills after work (technical support for Cognos). So maybe I am not a good programmer, but I am sure a good questioner :)

Updated on June 27, 2022

Comments

  • Michael Mao
    Michael Mao almost 2 years

    I've found a similar question on SO, however, that seems not exactly what I wanna achieve:

    Say, this is a sample XML file:

    <root>
        <item>
            <id isInStock="true">10001</id>
            <category>Loose Balloon</category>
        </item>
        <item>
            <id isInStock="true">10001</id>
            <category>Bouquet Balloon</category>
        </item>
        <item>
            <id isInStock="true">10001</id>
            <category>Loose Balloon</category>
        </item>
    </root>
    

    If I wanna get a "filtered" subset of the item elements from this XML, how could I use an XPath expression to directly address that?

    XPathExpression expr = xpath.compile("/root/item/category/text()");
    

    I now know this would evaluate to be the collection of all the TextContent from the categories, however, that means I have to use a collection to store the values, then iterate, then go back to grab other related info such as the item id again.

    Another question is : how could I refer to the parent node properly?

    Say, this xpath expression would get me the collection of all the id nodes, right? But what I want is the collection of item nodes:

    XPathExpression expr = xpath.compile("/root/item/id[@isInStock='true']");
    

    I know I should use the "parent" axis to refer to that, but I just cannot make it right...

    Is there a better way of doing this sort of thing? Learning the w3cschools tutorials now...

    Sorry I am new to XPath in Java, and thanks a lot in advance.