16
votes

Some of the nodes in an XML document have namespaces, specified with a defined prefix.

It is possible to specify local-name() in XPath 1.0 and so ignore namespaces.

However, I want to enable the writer of the XPath to find nodes using their full namespace-qualified name as an identifier.

The recommended way is to add namespace declarations in the invoking code (in my case, Java). But this means that the person writing Xpath does not have the ability to work with namespaces!

How do we find nodes by their fully qualified names using pure XPath?

4
If I understand the question correctly, you are asking why there is a need to declare a namespace using an instruction like addNamespace("abc","http://example.com") which then allows to do an Xpath query like /abc:node, instead of somehow using http://example.com directly in the query. Have I interpreted the question correctly?Jong Bor Lee
@Jong Bor Yes, that's it. It would be good to use the prefix abc directly in the XPath query after declaring that abc=example.com somehow within the XPath. I understand that XPath expressions are short and it would not be usual to insert definitions in it, but there is nothing technically preventing that from being possible in XPath.Joshua Fox
BTW good question, +1. Since prefixes are supposed to be merely insignificant syntactic sugar, whereas the namespace URIs are what's significant, you would think that it might be useful to match on a node name are namespace URI without having to mess with a prefix -- especially if XPath itself provides no way to declare a prefix.LarsH

4 Answers

15
votes

Not sure what you meant by "as an identifier".

How do we find nodes by their fully qualified names using pure XPath?

In XPath 1.0, by using local-name() and namespace-uri(), e.g.

"*[local-name() = 'foo' and namespace-uri() = 'http://my.org/ns/2.0']"

In XPath 2.0, there is a richer set of functions related to namespaces, e.g. namespace-uri-from-QName(). But I'm not sure they improve on the above for what you want.

6
votes

XPath 3.0, which is currently in working draft status, will include a literal expression for URI qualified QNames allowing to directly specify the namespace uri.

Here are some examples of EQNames:

  • pi is a lexical QName without a namespace prefix.
  • math:pi is a lexical QName with a namespace prefix.
  • "http://www.w3.org/2005/xpath-functions/math":pi specifies the namespace URI using a URILiteral; it is not a lexical QName.

I think Saxon 9.3 includes a preview implementation of xpath 3.0 which should be usable through the java api.

1
votes

You can use namespaces during your XPath queries. In Java, what you need to provide is an implementation of NamespaceContext if you also want to use prefixes in those queries instead of the fully qualified namespace all the time. Just add an instance of NamespaceContext to your XPath - I'll assume you use the standard JDK implementation - but the concept is applicable to Jaxen or others as well.

Then you can perform queries such as //customns:Element.

If you don't or can't use a NamespaceContext (for whatever reason) then the only solution seems to be using the local-name and namespace-uri functions:

Document doc = ...;
XPath xp = XPathFactory.newInstance().newXPath();
String name = "Element";
String ns = "http://www.custom.org/#";
String expr = "//*[local-name() = '"+name+" and namespace-uri() = '"+ns+"']";
Node node = ((NodeList)xp.evaluate(expr, doc, XPathConstants.NODESET)).item(0);
0
votes

The spec for XPath 3.0 says:

Q{http://www.w3.org/2005/xpath-functions/math}pi

This works at this moment (October 2015) for example in eXist-db.