I was working on an Azure utility with Johan on Friday, which had to deal with the XML responses provided by the Service Management REST API. XML like this:
<HostedServices xmlns="http://schemas.microsoft.com/windowsazure"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<HostedService>
<Url>https://management.core.windows.net/GUID/services/hostedservices/foo</Url>
<ServiceName>foo</ServiceName>
</HostedService>
</HostedServices>
Pop quiz: what would break if they left that xmlns attribute out of the root element?
Answer: Nothing. Nothing at all. XML namespaces are just used when you've got two or more schemata in a single XML document and the same symbol name might be defined by in more than one of them. Maybe, as in Tim Bray's original post on the subject, you're mixing book data with HTML and both data structures involve titles.
Because it's there…
It seems to be required in some circles – Microsoft included – to add an xmlns declaration in any and all XML, regardless of how small or self-contained it may be. And I suppose that, in and of itself, wouldn't really annoy me that much. But, try and process the XML above using Microsoft's own LINQ to XML classes (.NET 3.5 and above) and will it work?
Console.WriteLine("Starting...");
foreach (var element in xml.Elements("HostedService"))
{
Console.WriteLine(element.Element("ServiceName"));
}
Starting...
Press any key to continue...
No.
Why not?
Because all these element names are actually part of a custom namespace, and LINQ to XML honours these namespaces most particularly.
So, how to make this code work? (You'll like this.)
foreach (var element in xml.Elements(xml.GetDefaultNamespace() + "HostedService"))
{
Console.WriteLine(element.Element(element.GetDefaultNamespace() + "ServiceName").Value);
}
I'm not even joking. The default namespace for all children of an element can be obtained by calling GetDefaultNamespace on the element. Adding this to the start of a string returns a namespace-qualified XName which will then resolve correctly. (Don't get me started on what the LINQ to XML team did with operator-overloading; I don't know if it was strictly necessary for the LINQ side of it, but it's an unintuitive, undiscoverable pain in the neck as far as I'm concerned.)
Just to be absolutely clear about this: there is no way to have an element with an XML element that is not either in the default namespace or in an explicitly specified namespace.
So WHY doesn't LINQ to XML just apply the default namespace automatically? I'd guess it's because by the time the XElement method gets the value you're supplying as a string, it's been converted into an XName by the implicit conversion operator, which has no knowledge of the context.
Quick fix
Anyway, it's simple enough to get around once you realise what's amiss:
public static class XElementExtensions
{
public static XElement GetElement(this XElement element, string name)
{
return element.Element(element.GetDefaultNamespace() + name);
}
public static IEnumerable<XElement> GetElements(this XElement element, string name)
{
return element.Elements(element.GetDefaultNamespace() + name);
}
}
Unfortunately, the compiler honours the implicit conversion from string to XName before it honours extension methods, otherwise I could call these methods Element() and Elements() and everything would just work. Never mind.
HTH.