Reputation: 2048
The online XPath tester works similar to my code below for the given XML and XPath (doesn't match anything): http://www.xpathtester.com/xpath
import java.io.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
class test {
public static void main(String[] args) throws Exception {
XPathExpression expr = XPathFactory.newInstance().newXPath().compile(
"/A[namespace-uri() = 'some-namespace']"); // This does not select anything, replacing A with * does
// This XPath selects as expected (in all parsers mentioned): /*[namespace-uri() = 'some-namespace']
String xml = "<A xmlns=\"some-namespace\"> </A>";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
Document doc = factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
System.out.println("Number of nodes selected: " + nodes.getLength());
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println("Node name: " + nodes.item(i).getNodeName());
}
}
}
The above code does not select anything regardless of whether the document factory is namespace aware.
Is that according to the XPath standard? Or an implementation nuance?
This resource mentions the below:
Indeed, when the XML document uses the default namespace, the XPath expression must use a prefix even though the target document does not.
To verify that, I changed the XPath to include a prefix like so:
/p:A[namespace-uri() = 'some-namespace']
and added a namespace resolver that returned URI some-namespace for the prefix p, and that worked.
1) Is there a way of making XPath expressions without prefixes work on documents that have default namespaces?
2) How does the [second XPath tester][3] work? (This tester doesn't conform to the standard)
Note: In my application, I cannot control the document and XPath that I receive. But both are guaranteed to be valid.
Upvotes: 1
Views: 133
Reputation: 111716
For your sample XML,
<root>
<A xmlns="some-namespace"> </A>
<A xmlns="some-namespace2"> </A>
</root>
this XPath,
//A
should select nothing, yet on Freeformatter.com, it selects
<A xmlns="some-namespace2"> </A>
which is WRONG.
Therefore, full-stop, don't use Freeformatter.com. Don't try to work around this – simply don't use that service as it cannot be trusted to evaluate XPath in a conformant manner.
1) Is there a way of making XPath expressions without prefixes work on documents that have default namespaces?
You can
local-name()
[not recommended]local-name()
and namespace-uri()
[ok, but verbose], orFor further details, including examples of how to define a namespace prefix in many different hosting languages, see How does XPath deal with XML namespaces?
In my application, I cannot control the document and XPath that I receive (it is guaranteed to be valid). So I have to work with whatever XPath is sent to me. I'm guessing the answer to my question would be no then.?
If you're asking if there's a way to have //A
to select a node from the above sample XML and still be conformant to XPath, then the answer is indeed no.
Upvotes: 1