1

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());        
        }
    }
}

Link to Ideone

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.


Questions:

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.

Rushil Paul
  • 2,010
  • 4
  • 26
  • 39

1 Answers1

1

Freeformatter.com XPath anomaly

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.


XPath namespaces in general

1) Is there a way of making XPath expressions without prefixes work on documents that have default namespaces?

You can

  1. Defeat namespaces via local-name() [not recommended]
  2. Honour namespaces via local-name() and namespace-uri() [ok, but verbose], or
  3. Define a namespace prefix via various mechanisms of the hosting language library [prefered but varies per XPath hosting system]

For further details, including examples of how to define a namespace prefix in many different hosting languages, see How does XPath deal with XML namespaces?


For a given, fixed XPath can selection disregard 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.

kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • Yes I thought it must be wrong. And any ideas about my other question? – Rushil Paul Jan 04 '18 at 15:16
  • Answer updated to address your more general namespaces in XPath question too. – kjhughes Jan 04 '18 at 15:43
  • 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.? – Rushil Paul Jan 05 '18 at 07:08
  • Answer update yet again to address your more specific question about disregarding namespaces without changing the XPath. – kjhughes Jan 05 '18 at 12:41
  • I am asking if there is a way to have /A[namespace-uri() = 'some-namespace'] select a node from the sample XML. Since this does not contain a prefix – Rushil Paul Jan 05 '18 at 20:52
  • You just said, *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.*** Now, you're back to asking about how to craft an XPath. Sorry, but I've answered three distinct questions for you already and am not going to continue to do so indefinitely here. If I've helped, please [**accept**](http://meta.stackoverflow.com/q/5234/234215) this answer and ask a new one regarding your latest (***fourth!***) variation. If I've not helped, I'm sorry, but I've got to move on. Good luck. – kjhughes Jan 05 '18 at 21:17
  • Well, one of the XPaths that I received was what I've used in the code snippet, and since I *cannot control what is passed to me*, I'm expected to somehow use that to select the nodes from that document. That was always part of my question. And my main question remains unchanged. It was perhaps misunderstood. I'll repeat my question here: Is there a way of making XPath expressions without prefixes work on documents that have default namespaces? – Rushil Paul Jan 05 '18 at 21:28
  • Also, once we had established that the tester on Freeformatter.com was not correct, I removed the info related to it. So the XPath //A was out of the question. – Rushil Paul Jan 05 '18 at 21:30
  • And since I cannot change the XPath, the answer to my first question must be no. I'll mark your answer as accepted – Rushil Paul Jan 05 '18 at 21:35