C# xml serializing

If you don’t think you’ll use ever use XML since we now live in the future think again. XML is very useful for sending data over network, especially when you don’t know the recipient. Serializing in C# is as easy as cake and as long as you decide the XML rules it takes 2 minutes to generate properly named XML-elements. The problem starts when you work with someone who keeps sending you poorly named XML and expects the same ¤!”#% back.

Not to worry, the .NET library makes it all incredibly easy to serialize. To take an example we’ll create a Person class and serialize it:

 
Person.cs

public class Person
{
    public int Age { get; set; }
 
    public string Name { get; set; }
 
    public List<string> NickNames { get; set; }
 
    public Person()
    {
        NickNames = new List<string>();
    }
}

We’ll create a class for generic serialization that looks like this:

GenericSerializer.cs

public class GenericSerializer
{
    /// <remark>
    /// I hate nested classes but I've never found a 
    /// use for this class outside of this situation
    /// </remark>
    private class Utf8StringWriter : StringWriter
    {
        public override Encoding Encoding
        {
            get { return Encoding.UTF8; }
        }
    }
 
    public static string Serialize<T>(T obj)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        using (StringWriter writer = new Utf8StringWriter())
        {
            serializer.Serialize(writer, obj);
            return writer.ToString();
        }
    }
 
    public static T Deserialize<T>(string xml)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        return (T)serializer.Deserialize(new StringReader(xml));
    }
}

Now, let’s use this in a very basic console application and look at the result:

Program.cs:

class Program
{
    static void Main(string[] args)
    {
        Person person = new Person();
        person.Name = "John Doe";
        person.Age = 27;
        person.NickNames.Add("Johnny");
        person.NickNames.Add("Doe-man");
 
        string xml = GenericSerializer.Serialize(person);
        Console.WriteLine(xml);
 
        Person deserializedPerson = GenericSerializer.Deserialize<Person>(xml);
 
        Console.WriteLine("Person name: {0}", deserializedPerson.Name);
        Console.Read();
    }
}

Output:

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://
www.w3.org/2001/XMLSchema">
  <Age>27</Age>
  <Name>John Doe</Name>
  <NickNames>
    <string>Johnny</string>
    <string>Doe-man</string>
  </NickNames>
</Person>
Person name: John Doe

Now, the serialization worked like a charm. The array of nicknames looks pretty sad though and the elements are named according to the array type. If we need to control it, such as making Name and Age attributes instead of elements and changing the nicknames structure, we can use attributes in the Person class to explain to the serialization process how to handle the data:

[XmlRoot("person")]
public class Person
{
    [XmlAttribute("age")]
    public int Age { get; set; }
 
    [XmlAttribute("name")]
    public string Name { get; set; }
 
    [XmlArray("nicks")]
    [XmlArrayItem("nick")]
    public List<string> NickNames { get; set; }
 
    public Person()
    {
        NickNames = new List<string>();
    }
}

This would give the following output:

<?xml version="1.0" encoding="utf-8"?>
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://
www.w3.org/2001/XMLSchema" age="27" name="John Doe">
  <nicks>
    <nick>Johnny</nick>
    <nick>Doe-man</nick>
  </nicks>
</person>

There are a bunch of attributes that can be useful when explaining how to serialize the data. Here’s some:

XmlElement
Use the property as a XML element. If used on an array the array items are serialized without a root and straight into the current parent.

[XmlElement("age")]
public int Age { get; set; }
 
//<person>
//   <age>27</age>
//</person>

XmlAttribute
Use the property as a XML attribute.

[XmlAttribute("name")]
public string Name { get; set; }
 
//<person name="John Doe" />

XmlArray
Use the property as an array and set the name of the array root. Without the XmlArrayItem attribute the content is described by its type.

[XmlArray("nicks")]
public List<string> NickNames { get; set; }
 
//  <NickNames>
//    <string>Johnny</string>
//    <string>Doe-man</string>
//  </NickNames>

XmlArrayItem
Name the items of the array to serialize. Preferably used with XmlArray. If XmlArray is not used the root will be named according to the property name and the items according to this attribute value.

[XmlArray("nicks")]
[XmlArrayItem("nick")]
public List<string> NickNames { get; set; }
 
//  <nicks>
//    <nick>Johnny</nick>
//    <nick>Doe-man</nick>
//  </nicks>

XmlIgnore
A useful attribute if your representation class contains properties that you don’t want to use in serialization/deserialization. Any property marked with this attribute will be ignored.

These are some of the basics in XML serialization in C#. I will be writing a couple of more articles on the subject where I will be more specific (such as how to skip serializing properties conditionally and how to work with inheritance in serialization).

Extra example
I just thought I’d add an extra example, as it can be handy, on what to do if you get data from someone else that you need to deserialize. What if we get an XML file that looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<catalog>
  <books>
    <book isbn="1234-5-513-234">
      <title>A Tale Of Two Cities</title>
      <author>Charles Dickens</author>
      <publishingYear>1859</publishingYear>
    </book>
    <book isbn="4433-1-982-123">
      <title>The Catcher In The Rye</title>
      <author>J. D. Salinger</author>
      <publishingYear>1951</publishingYear>
    </book>
    <book isbn="9182-3-515-143">
      <title>How The Steel Was Tempered</title>
      <author>Nikolai Ostrovsky</author>
      <publishingYear>1932</publishingYear>
    </book>
    <book isbn="1999-8-313-532">
      <title>Confucius From The Heart</title>
      <author>Yu Dan</author>
      <publishingYear>2006</publishingYear>
    </book>
  </books>
</catalog>

Well, all we have to do is create two classes, Catalog and Book, and give them the corresponding properties and attributes:

Book.cs

namespace XmlSerializationTest
{
    [XmlType("book")]
    public class Book
    {
        [XmlAttribute("isbn")]
        public string ISBN { get; set; }
 
        [XmlElement("title")]
        public string Title { get; set; }
 
        [XmlElement("author")]
        public string Author { get; set; }
 
        [XmlElement("publishingYear")]
        public int PublishingYear { get; set; }
    }
}

Catalog.cs

namespace XmlSerializationTest
{
    [XmlRoot("catalog")]
    public class Catalog
    {
        [XmlArray("books")]
        [XmlArrayItem("book")]
        public List<Book> Books { get; set; }
 
        public Catalog()
        {
            Books = new List<Book>();
        }
    }
}

This would be all you need. As I’m just making an example I saved the XML as ‘Data.xml’ in my project as an embedded resource and read it like this:

namespace XmlSerializationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Stream stream = Assembly.GetExecutingAssembly()
                .GetManifestResourceStream("XmlSerializationTest.Data.xml");
            using (StreamReader reader = new StreamReader(stream))
            {
                string xml = reader.ReadToEnd();
                Catalog catalog = GenericSerializer.Deserialize<Catalog>(xml);
            }
 
 
            Console.Read();
        }
    }
}

I used the GenericSerializer described earlier in this article and just checked that it actually deserialized correctly, which it did. Good luck!