This one still keeps bugging me. I've done some testing now, so hopefully I can help you with this.
This is the source from Microsoft, which is the key to the problem
The important paragraph is here:
XPath treats the empty prefix as the null namespace. In other words, only prefixes mapped to namespaces can be used in XPath queries. This means that if you want to query against a namespace in an XML document, even if it is the default namespace, you need to define a prefix for it.
In essence, you have to remember the XPath parser uses the Namespace URI - with the design that the prefix is interchangeable. This is so, when programming, you can assign whatever prefix we want - as long as the URI matches.
For clarity with examples:
Example A:
<data xmlns:nsa="http://example.com/ns"><nsa:a>World</nsa:a></data>
This has a NULL default URI (xmlns=
is not defined). Because of this /data/nsa:a
returns "World".
Example B:
<data xmlns:nsa="http://example.com/ns" xmlns="https://standardns/"><nsa:a>World</nsa:a></data>
This document has a named default prefix https://standardns/
. XPathNavigator.Execute
with /data/nsa:a
therefore returns no results. MS considers that the XML namespace uri for data
should be NULL, and the namespace URI for data
is actually "https://standardns/". Essentially XPath is looking for /NULL:data/nsa:a
- although this won't work, as you can't refer to the NULL URI as "NULL" as a prefix. NULL prefix is the default in all XPath - hence the issue.
How do we solve this?
XmlNamespaceManager result = new XmlNamespaceManager(xDoc.NameTable);
result.AddNamespace("DEFAULT", "https://standardns/");
result.AddNamespace("nsa", "http://example.com/ns");
In this way, we can now refer to a as /DEFAULT:data/nsa:a
Example C:
<data><a xmlns="https://standardns/">World</a></data>
In this example data
is in the NULL namespace. a
is in the default namespace "https://standardns/". /data/a
should not work, according to Microsoft, because a
is in the NS https://standardns/
and data
is in the namespace NULL. <a>
is therefore hidden (except by doing weird "ignore the namespace" hacks) and cannot be selected upon as-is. This is essentially the root cause - you should not be able to select "a" and "data" with no prefixes for both, as this would assume that they were in the same namespace, and they aren't!
How do we solve this?
XmlNamespaceManager result = new XmlNamespaceManager(xDoc.NameTable);
result.AddNamespace("DEFAULT", "https://standardns/");
In this way, we can now refer to a as /data/DEFAULT:a
as data is selected from the NULL namespace, and a is selected from the new prefix "DEFAULT". The important thing in this example is that the namespace prefix does not need to remain the same. It's perfectly acceptable to refer to a URI namespace with a different prefix in your code, as to what is written in the document you are processing.
Hope this helps some people!