Tutorial: Xml Serialization, Part 1

Posted by Matt | Filed under , , ,

The best feature about C# has got to be Xml Serialization.

Creating an Xml reader/writer in C++ using MSXML or LibXml takes significant time and debugging.  Creating the same Xml reader/writer in C# using classes is very easy.  Admittedly, if I am using C++, I have no problems using LibXml, but if given a choice, I'd use C# first.

To make a class Xml Serializable, you need to:

  1. make the class public, and
  2. give it the Serializable attribute.

The follow class can be read/written to Xml:

[Serializable]
public class Family
{
}

This class won't do anything, but you can use the follow code to write it to file:

Family f = new Family();
// TODO: Fill the family object

XmlSerializer xmlSerializer = new XmlSerializer(typeof(Family));
TextWriter writer = new StreamWriter("Family.xml");
xmlSerializer.Serialize(writer, f);
writer.Close();

and the following code to read from file:

XmlSerializer xs = new XmlSerializer(typeof(Family));
TextReader reader = new StreamReader("Family.xml");
Family f = (Family)xs.Deserialize(reader);

The resulting Xml file will look like this:

<?xml version="1.0" encoding="utf-8"?>
<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema" />

Pretty basic and not much fun.

Every family I know has a family name, so let's add a name to the family:

[Serializable]
public class Family
{
  public string Name { get; set; }
}

(Please note that I am using C# 3.5 short-notation for members.)

If we set the family name and serialize it, we'll get the following:

<?xml version="1.0" encoding="utf-8"?>
<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Smith</Name>
</Family>

Notice that the Name member of Family became a child element of Family in the Xml tree.  This is the default behaviour of all public members.  By default, C# will serialize all public members of a class as sub-elements.

In my case, I'd prefer Name to be an attribute of family instead of a sub-element.  To do this, I use the [XmlAttribute] attribute on the Name member:

[Serializable]
public class Family
{
  [XmlAttribute]
  public string Name { get; set; }
}

to get:

<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        Name="Smith" />

This is now more to my liking.

Let's add some family members to this family.  First, define a family member class:

[Serializable]
public class FamilyMember
{
  public string Name { get; set; }
  public short Age { get; set; }
}

and add a list of family members to our family class:

private List<FamilyMember> _members = new List<FamilyMember>();
public List<FamilyMember> Members
{
  get { return _members; }
  set { _members = value; }
}

If we add some members to our family, and serialize, we get the following:

<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        Name="Smith">
  <Members>
    <FamilyMember>
      <Name>John</Name>
      <Age>51</Age>
    </FamilyMember>
    <FamilyMember>
      <Name>Mary</Name>
      <Age>50</Age>
    </FamilyMember>
  </Members>
</Family>

You'll notice that we have 2 family members each with their own data.

In part 2, we will specialize the family members into derived classes of FamilyMember.

Comments

April 24, 2009 11:34

Ka-blogs

Thank you for the tutor. It helps a lot.

Ka-blogs United States

Comments are closed