Put Down the XmlNode and Step Away From the StringBuilder

Posted: 2/12/2008 2:29:33 PM

I'm sure there are plenty of you out there who have your boss hankering to use some of that "Xml Stuff". Sometimes we get sheltered in our own little world and haven't actually had to work with a whole lot of xml data that wasn't already wrapped up by the Project Settings object created by Visual Studio. So naturally, you'd probably go to the "tubes" and search for some additional information. Undoubtedly, you will run across pages telling you how to construct some Xml in C# by creating a new XmlDocument and adding XmlNode children which will have attributes and subnodes and namespaces, ad infinitum. And you'll realize you now have some of the world's fugliest code. So you decide, "oh, well xml is really similar to html, I'll just build it using a StringBuilder" and you end up with slightly less fugly code, that is until you try to read it back in.

These methods are completely unnecessary. PUT DOWN THE XMLNODE AND STEP AWAY FROM THE STRINGBUILDER. Slowly move your hand to the mouse and scroll down to read about the easiest way to write and read Xml in the .net framework.

Ok, quick show of hands: who thinks working with simple .net business model objects is brain dead easy? Alright, if your hand isn't up, you are beyond hope, please leave now. Of course, working with simple objects is about the simplest exercise for code next to "Hello World". If you can create a .net object that models the xml you want to store, you are 95% done with outputting well formed Xml.

Example: If I wanted to store information about a few people and their pets I would create three classes:
public class PetClub
{
public List<Person> Members { get; set; }
}

public class Person
{
public string Name { get; set; }
public List<Pet> Pets { get; set; }
}

public class Pet
{
public string Name { get; set; }
public string Type { get; set; }
}
To get an Xml representation of an instance of PetClub, all you have to do is use the XmlSerializer found in the System.Xml.Serialization namespace. I've wrapped up all the necessary code into a short utility method.
public static string ConvertToXml(object item)
{
XmlSerializer xmlser = new XmlSerializer(item.GetType());
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
xmlser.Serialize(ms, item);
UTF8Encoding textconverter = new UTF8Encoding();
return textconverter.GetString(ms.ToArray());
}
}

Simply calling: ConvertToXml(myPetClubInstance) will spit back the following xml:

<PetClub xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Members>
    <Person>
      <Name>Jon</Name>
      <Pets>
        <Pet>
          <Name>Chester</Name>
          <Type>Savannah Cat</Type>
        </Pet>
        <Pet>
          <Name>Abby</Name>
          <Type>Domestic Miniature Panther</Type>
        </Pet>
      </Pets>
    </Person>
    <Person>
      <Name>Dan</Name>
      <Pets>
        <Pet>
          <Name>Lucy</Name>
          <Type>Semi-sweet Chocolate Lab</Type>
        </Pet>
      </Pets>
    </Person>
  </Members>
</PetClub>


At this point you might be saying: "That is cool and all, Jon, but this looks like a lot of xml to be outputting for such little actual data. And what if I want to have more control over xml element naming". Dear friend, let not your heart be troubled for there is help on the way. By adding some simple Property Attributes to our classes we can completely change how our xml is constructed.  We can have the object in whatever form is most convienient for our program while still allowing us to interoperate with an xml document created by a different application with a different idea of what good names are.

Changing our two classes to:
public class Person
{
[XmlElement("FirstName")]
public string Name { get; set; }
public List<Pet> Pets { get; set; }
}

public class Pet
{
[XmlAttribute("Name")]
public string Name { get; set; }
[XmlAttribute("Breed")]
public string Type { get; set; }
}

Will output this xml:

<PetClub xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Members>
    <Person>
      <FirstName>Jon</FirstName>
      <Pets>
        <Pet Name="Chester" Breed="Savannah Cat" />
        <Pet Name="Abby" Breed="Domestic Miniature Panther" />
      </Pets>
    </Person>
    <Person>
      <FirstName>Dan</FirstName>
      <Pets>
        <Pet Name="Lucy" Breed="Semi-sweet Chocolate Lab" />
      </Pets>
    </Person>
  </Members>
</PetClub>



Pretty simple, huh? Can you imagine how difficult it would be to make these changes via XmlNodes or a StringBuilder? There are about 10 other property attributes available for xml serialization, including the very useful XmlIgnore() attribute which makes the appropriate property not serialized. I'll leave the rest of the research up to you.

And I almost forgot, to read your xml back into an object use the following method:

public static T FromXml<T>(string xml)
{
XmlSerializer xmlser = new XmlSerializer(typeof(T));
using (System.IO.StringReader sr = new System.IO.StringReader(xml))
{
return (T)xmlser.Deserialize(sr);
}
}

Sample Code - XmlSerializerSample.cs (2.33 KB)



Tags: Tips and Tricks