Reputation: 55
I have the following xml
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<abc:root-example xmlns:abc="http://www.example.com/abc">
<abc:test-object Name="DesiredObject">
<root xmlns="http://www.example.com">
<value>Hello world</value>
</root>
</abc:test-object>
</abc:root-example>
and the following java code
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlFilePath.toFile());
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String s) {
if (s.equals("abc")) {
return "http://www.example.com/abc";
}
return null;
}
@Override
public String getPrefix(String s) {
return null;
}
@Override
public Iterator<String> getPrefixes(String s) {
return null;
}
});
XPathExpression expr = xpath.compile("//abc:test-object/root");
Node node = (Node) expr.evaluate(doc, XPathConstants.NODE);
The final node here always ends up being null. If I remove xmlns="http://www.example.com"
from the root
node, then the evaluation returns the expected node. It's unclear to me how I properly format the XPath request to get the node. I believe it has something to do with root
using a different default namespace, but am having difficult figuring it out.
Upvotes: 1
Views: 841
Reputation: 10539
I've found the following:
In getNamespaceURI(...)
, the value null
is returned if the namespace prefix is not abc
. But the default namespace's URI is http://www.example.com
instead.
In the XPath query, no namespace prefix given for root
. This is reasonable since it should use the default namespace, however it seems necessary to explicitly give an empty prefix now: :root
.
Applying both changes will make the code return the node.
xpath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String s) {
if (s.equals("abc")) {
return "http://www.example.com/abc";
}
return "http://www.example.com";
}
@Override
public String getPrefix(String s) {
return null;
}
@Override
public Iterator<String> getPrefixes(String s) {
return null;
}
});
XPathExpression expr = xpath.compile("//abc:test-object/:root");
Node node = (Node) expr.evaluate(doc, XPathConstants.NODE);
System.out.println(node == null ? "null" : node); // just to show
Output:
[root: null]
Update: As Martin Honnen points out, although accepted by javax.xml.xpath
, :root
is not a valid XPath expression. Also, javax.xml.xpath
is only XPath 1.0 compliant. I've found another, rather verbose way to select the node with //abc:test-object/*[local-name()=\"root\"]
, but it probably makes more sense to either just
Upvotes: 1