This is old hat and more of a bookmark for me when I bump into this each time I'm working with XML documents that have default namespace declared. But I thought I'd share anyway.
Take the following simple XML document:
<?xml version="1.0" encoding="utf-8" ?><products xmlns="urn:backoffice:products"> <product id="100-1100"> <description>JVC CD Player</description> <price>120.99</price> <category>100</category> </product> <product id="100-1101"> <description>Sony CD Player</description> <price>122.99</price> <category>100</category> </product> <product id="100-1102"> <description>LG DVD Player</description> <price>109.99</price> <category>110</category> </product> <product id="100-1103"> <description>Technics DVD Player</description> <price>199.99</price> <category>110</category> </product></products>
You might expect that the code to select all the product nodes would look like:
XmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable());nsm.AddNamespace("", "urn:backoffice:products");XmlNodeList productList = products.SelectNodes("/products/*", nsm);
The above seems the logical thing to do because the default namespace doesn't have a prefix so you naturally go ahead and specify String.Empty (or "", whichever) when adding it to the namespace manager. Additionally if you execute the code and breakpoint after setting adding the namespace and inspect the DefaultNamespace property of 'nsm' you'll see that it's even set to "urn:backoffice:products". However, the XmlNodeList returned from products.SelectNodes has no nodes.
This confused the hell out of me when I first encountered it way back when and I tripped up on it again last week. What's going on?
Basically XPath expressions select nodes that are either in a namespace or in the empty namespace. The XPath expression '/products/*' is selecting nodes from the empty namespace (xmlns="") but the document above is defining a default namespace of 'urn:backoffice:products' which is not the empty namespace. We have to tell XPath to select nodes from the namespace 'urn:backoffice:products' otherwise no nodes will be returned.
So how do we do this?
We add the namespace with an arbitrary prefix and the XmlNamespaceManager is used to expand 'p' to the default namespace name which then brings the nodes we're interested in into scope.
One thing still puzzles me though is the purpose of the DefaultNamespace property in the XmlNamespaceManager and I guess some digging around will uncover it's intentions because the MS docs are pretty vague.
Remember Me
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.