As any fule no, QNames are how XML does namespaces. Where a namespace has been declared:
<c:cml xmlns:c="http://www.xml-cml.org/schema/>
and the "c" prefix on the element name is associated, via the xmlns attribute, with the namespace URI. This is trivially manipulable with any namespace-aware tool.
So far so good. However, when QNames are used in content (typically, as an attribute value) then the situation is more complex. The two nodes below are equivalent under QName-in-content processing.
<c:cml xmlns:c="http://www.xml-cml.org/schema" att="c:comp"/> <d:cml xmlns:d="http://www.xml-cml.org/schema" att="d:comp"/>
This usage is blessed by the W3C, http://www.w3.org/2001/tag/doc/qnameids.html, and XSLT depends on it working.
But it's significantly harder to work with using most XML toolkits.
node()[@att='string']
The above XPath returns all nodes which have att="string". However, it turns out that matching on a namespace-resolved QName needs the following:
node()[substring-after(@att, ':')='comp' and @att[../namespace::* [name()=substring-before(../@att,':')] ='http://www.xml-cml.org/schema'] ]
if you only allow for prefixed QNames (eg c:comp above). If you want to be able to match unprefixed QNames as well, that is, QNames in the default namespace:
<cml xmlns="http://www.xml-cml.org/schema" att="comp"/>
then you need to extend the expression to the following:
node()[(substring-after(@att, ':')='comp' and @att[../namespace::* [name()=substring-before(../@att,':')] ='http://www.xml-cml.org/schema']) or (@att='comp' and and namespace::*[name()=''] ='http://www.xml-cml.org/schema') ]
which is hardly transparent!
Much as I think XPath 2 is a bad idea in general, this is one area where it is a significant step forward; it offers node functions:
which will do what they suggest. Of course XPath 2 then buggers things up again by saying:
In XPath Version 2.0, the namespace axis is deprecated and need not be supported by a host language
— XML Path Language (XPath) 2.0
Who needs backwards compatibility anyway?
But since libxml2 doesn't support XPath2, I don't propose to worry very much about it.
In any case, unwieldy though the above solutions are, they work correctly.