C# Reading XML With Namespace May 21
I've said it before and I'll say it again: .NET is a ghetto. It's my experience that once your application becomes non-trivial, there is no tried-and-true way of accomplishing a given task.
You either have to piece together what feel like desparate code in order to accomplish the most common of use cases. Case in point is using XPath to read data in XML.
Say you have this XML response:
<?xml version="1.0" encoding="utf-8"?>
<UserResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<User xmlns="http://halo.com/schemas/custom/users/GetUser_V1">
<Result>"Successful"</Result>
<Name>John-117</Name>
<Age>Unknown</Age>
<Rank>Master Chief Petty Officer</Rank>
</User>
<UUID xmlns="http://halo.com/schemas/custom/users/GetUser_V1">
{61D25ABC-CD96-4838-9406-C867B6D07449}
</UUID>
</UserResponse>
Using C#, parsing this data should be an easy task - right? You should be able to do something like this?
HaloService haloService = new HaloService();
string response = haloService.ExecuteCall("{61D25ABC-CD96-4838-9406-C867B6D07449}");
XmlDocument results = new XmlDocument();
results.LoadXml(response);
if (results.SelectSingleNode("//UserResponse/User/Result").InnerText == "Successful") {
string Name = results.SelectSingleNode("//UserResponse/User/Name").InnerText;
}
But does that work in .NET C#? No.
Why? It doesn't work because the XML response has a namespace separating the key data notes. Here the XML namespace is:
http://halo.com/schemas/custom/users/GetUser_V1
So what are your options:
You really only have two options when confronted with this challenge. The first is to you XMLNamespaceManager. I don't care for that route as you'll see below.
The final option is to strip the Namespaces using Regex. I prefer this route and you'll see why.
Use XmlNamespaceManager
When using XPath in .NET (via SelectNodes or SelectSingleNode) on XML with namespaces you need to:
- Provide your own XmlNamespaceManager
- Explicitly prefix ALL elements in your XPath expression which are in the namespace
You do so in a similar fashion as below:
. . .
XmlDocument results = new XmlDocument();
results.LoadXml(response);
XmlNamespaceManager ns = new XmlNamespaceManager(results.NameTable);
ns.AddNamespace("ns",
"http://halo.com/schemas/custom/users/GetUser_V1");
string Result = results.SelectSingleNode(
"//UserResponse/ns:User/ns:Result", ns).InnerText;
. . .
This gets you the data, but it's clumsy and has several disadvantages. First, if you don't control the web service (which many people don't), the namespace could change on you at anytime.
When that happens your hardcoded namespace WILL break and you will have production downtime. Second, you can't reuse XPath that was previously valid. Finally, the namespaced XPath expression is less readable and therefore, less maintainable.
The XPath implementation in SelectNodes and SelectSingleNode should really be more flexible. Using familiar methods should not shock developers or lead to unmaintainable code. It simply shouldn't
Strip The Namespaces Using Regex
Regex is like violence - if it doesn’t solve your problems, you are not using enough of it. Generally, I don't condone the use of unnecessary Regex.
This isn't one of those scenarios. Here, Regex was not only necessary, it was downright welcomed:
string filter = @"xmlns(:\w+)?=""([^""]+)""|xsi(:\w+)?=""([^""]+)""";
response = Regex.Replace(response, filter, "");
XmlDocument results = new XmlDocument();
results.LoadXml(response);
string Name = results.SelectSingleNode("//UserResponse/User/Name").InnerText;
Here, we remove any XML Namespace (xmlns) declaration before loading the XML. Once you do that, you can read the XML using the XPath expression you expected to use in the first place.
The pros are quick and apparent. First, your application won't break if the owner of the web service need to change their namespace (this could easily happen). Second, you cna reuse previously developed XPath expressions without issue. Finally, the code is simply more readable - one to one - with the original XML.
Really hope this helps save someone some much needed development time. Wish I had this article, it definitely would have saved me time.
Code Long & Prosper!




Version 1.0 of TechOctave
Version 2.0 of TechOctave JavaScript Gauges, Circa Late 2010

Version 1.2 of TechOctave JavaScript Charts, Circa Late 2011













Pont du Gard: A masterpiece of Roman aqueduct engineering.

Galileo facing the Roman Inquisition, Cristiano Banti 1857




