Attempting to use XPath with an XML file that has a default namespace declared for the root node.
Example code:
final SAXBuilder builder = new SAXBuilder();
final Document document = builder.build(originalFile);
final XPathFactory xFactory = XPathFactory.instance();
final String expression = String.format("//section[@label='%s']/section/section", LABEL);
final XPathExpression<Element> sectionExpression = xFactory.compile(expression, Filters.element());
final List<Element> sections = sectionExpression.evaluate(document);
Sections is empty.
Snippet of the XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://www.stellent.com/sitestudio/Project/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.stellent.com/sitestudio/Project/ http://www.stellent.com/sitestudio/ss_project_schema.xsd">
<section label="Index">
<section label="xyz">
<section label="child">
...
</section>
</section>
</section>
</project>
Removing the xmlns="http://www.stellent.com/sitestudio/Project/"
works but isn't a solution!
Why isn't XPath able to know about this default namespace? Also, why does it care?
Better yet, how can I generically fix this?
Thank you for any insight.
JDOM is doing the right thing. This is a FAQ, and not just for JDOM, but for XPath in general. The XPath specification is (somewhat) clear on this (I have bolded the relevant part):
From an XPath perspective, what this means is that the Namespace handling for rules in the XPath expression are not actually the same as the nodes in the XML. For all XPath expressions you need to define (duplicate) the namespace context for the expression, and the prefixes you use for the expression are actually completely independent to the ones used in the actual XML document.
You need to 'invent' a namespace prefix for your default namespace, and use that prefix in your expression (Here I have invented the namespace prefix
ns
):