Given:
public class XPathTest {
public static void main(String args[]) throws Exception {
String xmlString
= "<a>"
+ "<b c=\"1\"/>"
+ "<b c=\"2\"/>"
+ "</a>";
ByteArrayInputStream bis = new ByteArrayInputStream(xmlString.getBytes());
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(bis));
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//b");
NodeList nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
dumpNodeList(nl);
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
NodeList nl2 = (NodeList) expr.evaluate(n, XPathConstants.NODESET);
dumpNodeList(nl2);
}
}
public static void dumpNodeList(NodeList nl) {
System.out.println("NodeList length = " + nl.getLength());
for (int i = 0; i < nl.getLength(); i++) {
System.out.println("Node #" + i);
Element e = (Element) nl.item(i);
System.out.println("Name = " + e.getTagName());
System.out.println("Attr = " + e.getAttribute("c"));
}
System.out.println();
}
}
Sample result:
NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2
NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2
NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2
I evaluate the XPath expression //b
, passing in the root document node to the evaluator. It, expectedly, returns the two b
nodes.
What I'm confused about is when I evaluate the same expression, but instead of passing in the root node as he parameter I pass in one of the children nodes I located earlier. According to XPathExpression.evaluate(Object item)
, it says Evaluate the compiled XPath expression in the specified context and return the result as the specified type.
The expression, //b
, means "give me all of the b
nodes".
Intuitively, I would think that if I pass in a Node to XPathExpression.evalute(Object item)
, that the expression would be evaluated starting with that node as its root for the "give me all" part, rather than the entire document. So I would expect a resulting NodeList of one node, not two.
But instead, I get the same two nodes as if from the entire document.
So, the two questions are:
Why is the expression being evaluated relative to the entire document, and not to just using the pass Node as a synthetic root for the evaluation?
How can I get the expression to evaluate using the passed in Node as the synthetic root for the evaluation?