Reputation: 27296
I am using Java with Saxon HE 9.4 so I can have XPath 2.0 support.
Given the following XML instance document:
<entities>
<entity>
<person>
James
</person>
</entity>
<entity>
<legalEntity>
ACME
</legalEntity>
</entity>
</entities>
I know I can get a list of the entity element tags by doing a:
XPathExpression expr = xpath.compile("/entities/entity/*");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodes.getLength() ; i++)
System.out.println("element name = "+ nodes.item(i).getNodeName());
The above will output:
element name = person
element name = legalEntity
... as expected.
However, the logic is spread in two places: the XPath expression itself, and the call to getNodeName
method. What I would like is an XPath expression that would return a generic list of results, which I could iterate over by calling some generic method (not getNodeName
).
This way, all the logic could reside in the XPath expression itself and my code could just keep the XPath strings in a file and process them at runtime to get lists of results.
Trying the XPAth expression /entities/entity/*/name()
only fetches the first value (person):
XPathExpression expr = xpath.compile("/entities/entity/*/name()");
System.out.println("element name = "+expr.evaluate(doc));
... and the code breaks at runtime if I try to cast that to a NodeList
:
XPathExpression expr = xpath.compile("/entities/entity/*/name()");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodes.getLength() ; i++) {
...
(the above fails with: net.sf.saxon.trans.XPathException: Cannot convert XPath value to Java object: required class is org.w3c.dom.NodeList; supplied value has type xs:string
)
So is there a generic way to get XPath expressions evaluate to list of results (which could be element tags, element values, attribute values and tags, etc.) so that the code iterating over these results is the same in all cases and doesn't have to differentiate between calls to getNodeName()
or getNodeValue()
?
Upvotes: 1
Views: 3187
Reputation: 163585
You're using the JAXP interface to XPath. This is designed for XPath 1.0, and only recognizes the XPath 1.0 data types (string, node-set etc). You want to do a query that returns a list of strings (or perhaps QNames), so you will need to use an API that supports such data types - specifically, you need to move to Saxon's s9api API.
In the s9api interface, the XPathSelector object (see http://www.saxonica.com/documentation/#!javadoc/net.sf.saxon.s9api/XPathSelector) implements Java's Iterable interface, so you can use it directly in a Java "for-each" instruction to process the results as a sequence of XdmItem objects; the XdmItems can be nodes or atomic values, in fact any type defined in the XPath 2.0 data model.
You can use s9api to run XPath expressions against either Saxon's native tree model (built using the s9api DocumentBuilder) or against external models such as DOM, JDOM, XOM etc. Using Saxon's native model is much faster than any of the external models.
Upvotes: 2