Why?I've been forced into engaging with XML in all its gory details recently, as part of my AzureKit project (more on which in another post). Being a big fan of all things LINQ, I started out trying to use the LINQ-to-XML framework. I had problems. This is not a fault of the framework; as a fundamental part of the .NET Framework it must provide a way to achieve everything, and that's not the same as providing a way to do things simply.
The REST API for Windows Azure uses a hybrid of the Atom syndication format and the ADO.NET Data Services format. Here is the XML required for an Insert to an Azure Table:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
I can't post the LINQ-to-XML code you need to use to create that small document, because I deleted it. Then I formatted the hard drive that it had been on. Then I burned it, just to be on the safe side. The code was not clean. The code was feculent.
The quickest example that I can give is that to use a prefixed namespace, you don't use new XElement("m:properties"); you use new XElement(parentElement.GetNamespaceForPrefix("m") + "properties"). Seriously. I'm just not doing that.
If you don't like an interface, wrap itFor these purposes, an XML tree is a collection of named elements, some of which have values, some of which have sub-elements, and each of which may have a number of attributes.
More importantly a single Atom entry does not involve "lists"; that is, there are not multiple children with the same name within a parent element, like this:
In fact, an Azure Atom entry is a lot like a dictionary, except with nesting.
I like dictionaries. In some other languages, I like hashes. But we're talking about .NET and C# here, so I like dictionaries.
XmlElementAsDictionaryI've created a very simple class which wraps around an XElement object and provides access to that element's children, attributes and value using the Dictionary paradigm. Into this class I have baked support for namespaces which does not violate the Principle of Least Astonishment.
Using this class to create the Azure/Atom XML element above looks like this:
var entry = new XmlElementAsDictionary("entry", "http://www.w3.org/2005/Atom");
entry["updated"].Value = DateTime.Now.ToString("s");
entry["content"].Attributes["type"] = "application/xml";
entry["content"]["m:properties"]["d:Address"].Value = "Mountain View";
entry["content"]["m:properties"]["d:PartitionKey"].Value = "mypartitionkey";
entry["content"]["m:properties"]["d:RowKey"].Value = "myrowkey1";
entry["content"]["m:properties"]["d:Timestamp"].Value = DateTime.MinValue.ToString("s");
entry["content"]["m:properties"]["d:Timestamp"].Attributes["m:type"] = "Edm.DateTime";
The class will also accept an XElement to its constructor, and so can be used for reading XML in this manner as well as writing.
Once complete, the element can be converted back into XML using ToElement() or ToDocument(), or to plain-text using ToString() (which gives the same result as calling ToElement().ToString().