August 03, 2007

LINQ: XElement and Namespaces

I had an opportunity to play with LINQ for XML and Google Maps recently. Quite a bit of fun actually. Anyway, I ran into a problem in that Google Maps encodes all of their XML in Namespaces. I hate Namespaces. I understand that somewhere there is a reason for namespaces to live -- but I still hate them. More than that, I hate having to query for them. XPath with Namespaces is just a pain beyond belief.

So one of the cool new objects you get in .NET 3.5 is XElement for reading xml and being able to use LINQ on it. But...what about querying with namespaces?

Here is how you do it:

Declare a XNamespace object with the namespace. In my case it looked like this:
XNamespace ns = "http://earth.google.com/kml/2.0";

Grab the XML, via a url, into an XElement node:
XElement resultNode = XElement.Load( url );

Now, I just wanted one node buried deap in the structure called "coordinates". This is how I grabbed it:
XElement coordinateNode = resultNode.Descendants( ns + "coordinates" ).First();

So that last line of code. I'm using the Descendants method to return all of the nodes in a flat list. I could have used resultNode.Descendants().Last() and gotten the node I wanted (since the coordinates node is the last node in the document -- but there isn't much of a guarantee that will always be the case.

So I'm asking the Descendants method for the "coordinates" node by name, and I'm prefixing that name with the namespace. Descendants returns an IEnumerable (a list), so I use the First() method to just give me the first instance.

Compared to XPath, this was a dream. But I still hate namespaces.

Here is all the code again in list:

XElement resultNode = XElement.Load( url );
XNamespace ns = "http://earth.google.com/kml/2.0";
XElement coordinateNode = resultNode.Descendants( ns + "coordinates" ).First();

2 comments:

Anonymous said...

Thank you. Very useful post.
Leonardo.

Anonymous said...

Thanks you! That was very helpfull.
George