XPath and XML Namespaces
It’s great that in C# code you can easily reference XML nodes using the XmlDocument’s built-in XPath support:
1 | XmlNode titleNode = doc.SelectSingleNode("/html/head/title"); |
But have you ever run into the situation where you call SelectSingleNode or SelectNodes and you get back nothing when you can see there are nodes there? The problem might be that the document is using XML Namespaces.
Consider this XML snippet:
1 2 3 4 5 | <urlset xmlns="http://www.google.com/schemas/sitemap/0.84"> <url> <loc>http://blog.stevex.net/</loc> </url> </urlset> |
If you attempt to retrieve nodes from this document using this code:
1 | XmlNode urlNodes = doc.SelectNodes("/urlset/url"); |
You might expect to get back a set of all the url nodes, but instead you get back nothing.
To query into a document that uses namespaces, you need to use an XmlNamespaceManager. The namespace manager takes care of mapping a prefix to a namespace, and lets you associate the nodes in the query with particular namespaces.
The following code would query the sitemap.xml:
1
2
3 XmlNamespaceManager nsMgr = new XmlNamespaceManager(myXmlDoc.NameTable);
nsMgr.AddNamespace("sm", "http://www.google.com/schemas/sitemap/0.84");
XmlNode urlNodes = doc.SelectNodes("/sm:urlset/sm:url");
If a page uses multiple namespaces then you’d have multiple calls to AddNamespace with different prefixes. Your query string can include nodes from different namespaces.
November 14th, 2005 at 8:39 am
Thank you!! I have been struggling with this for a couple of hours and now (at last!) it is working!
November 22nd, 2005 at 12:42 am
I am having similar problem but by xml doc is having 2 namespace attributes as given below
What should be XmlNamespaceManager for this one?
Thanks
MAKARAND
January 22nd, 2006 at 10:48 am
This was just what I needed to know. I have a document similar to this one, the documentation claims you can use “String.Empty”, for a default namespace (and thus, I assumed not need prefixes in the actual xpath expression).
Thanks, was just about to waste another hour on this non-issue
January 29th, 2007 at 9:38 am
I think you have a typo in your example
You write:
XmlNamespaceManager nsMgr = new XmlNamespaceManager(myXmlDoc.NameTable);
It shoud be, I think:
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
February 19th, 2007 at 12:30 am
Thank you SO MUCH.. I was about to give up all together on these stupid Namespaces! I found your document and had my code working within mere minutes..
Thanks again!
-Brad
August 14th, 2007 at 8:41 pm
THANK YOU THANK YOU THANK YOU THANK YOU. You saved me from /wrists. I’ve been looking and looking at my XPath and KNEW it was right. I had no idea that the namespace would muck things up.
Thanks again,
Lee
August 14th, 2007 at 8:48 pm
[...] was just about to /mywrists today when I found this post. I wanted to post to this blog to say thanks to SteveX for posting [...]
August 16th, 2007 at 1:18 pm
thanks for the info:
my code required a different implementation…
XmlNodeList urlLocNode = sitemap.SelectNodes(“/sm:urlset/sm:url/sm:loc”, nsMgr);
1) SelectNodes returns a XmlNodeList not an XmlNode
2) You need to use the overloaded version of the SelectNodes method to pass the XmlNamespaceManager object.
April 1st, 2008 at 12:40 am
[...] XPath and XML Namespaces oh my… I was just about to /mywrists today when I found this post. I wanted to post to this blog to say thanks to SteveX for posting [...]
February 6th, 2009 at 1:36 am
Thanks Steve. This post is REALLY very useful. I was struggling to get xmlnode by using xpath from last two days and i got this post . Thanks once again.
February 24th, 2009 at 4:21 pm
I thank you. My coworkers thank you. The cabinet I’ve been banging my head against for the last 2 hours thanks you. Cheers.
June 19th, 2009 at 4:12 pm
I only wish we could use the empty string for the namespace prefix like everyone else’s libraries use. It’s no fun rewriting tons of xpath to be compatible with Microsoft libraries. This took me days to figure out, and I found a MSFT reference page going back to ’03 where they realize it’s wrong (“by design”) and I guess they’ll never make their libraries work the same as everyone else’s. I love their tools but things like this really chafe.
January 7th, 2010 at 10:22 am
Thank you, It’s a great help for me.
I think you forgot to pass XmlNamespaceManager(nsMgr) to SelectNodes method:
XmlNode urlNodes = doc.SelectNodes(“/sm:urlset/sm:url”, nsMgr);
Thanks again.