We need you!

We're working hard on the next version of Developer Fusion. Let us know what you think we should be up to!

Members

Technology Zones

Articles

Hosted By

MaximumASP

Info

Rated
Read 42,066 times

Downloads

Related Categories

Customize XML Serialization using IXmlSerializable

XML Serialization in .NET provides an incredibly useful (and easy) way to turn objects into XML and back again. However, in some situations, you may need more control over how your object is serialized. Recently, I found myself needing to serialize an object that contained a number of property name/values - stored using a NameValueCollection. However, you can't serialize this using the XML serializer (see this KB article). I could have switched to using an array - at least for the serialization part - but this would have serialized the whole lot as a series of elements - and I wanted to do this using attributes.

For example, suppose I had the following XML:

<ObjectProperty Name="Test" ReadOnly="false">
    <ProviderInfo Name="SqlServer" TypeCode="VarChar" TypeSize="100" />
    <ProviderInfo Name="Access" TypeCode="VarChar" TypeSize="100" />
</ObjectProperty>

I wanted this to be turned into my ObjectProperty object (with properties Name,ReadOnly and an array of ProviderInfo objects). In addition, each ProviderInfo object has a Name property, and a NameValueCollection that I wanted populating with TypeCode mapped to VarChar and so on. My ProviderInfo object looked like this:

[Serializable]
public class ProviderInfo /* : IXmlSerializable */ {
  NameValueCollection _attributes;
  string _name;

  public ProviderInfo()
  {
  }

  public ProviderInfo(string name, NameValueCollection attributes)
  {
    this._name = name;
    this._attributes = attributes;
  }

  [XmlAttribute]
  public string Name
  {
    get { return _name; }
    set { _name = value; }
  }

  [XmlIgnore]
  public NameValueCollection Attributes
  {
    get { return _attributes; }
    set { _attributes = value; }
  }
}

In the end, this turned out to be simpler than I'd first feared, and the trick was to implement the IXmlSerializable interface (undocumented in .NET 1.1 - hopefully less so in .NET 2.0). The interface requires us to implement three methods; GetSchema(), ReadXml(XmlReader r) and WriteXml(XmlWriter r). When you implement the interface, these methods are called instead of .NET trying to serialize the object itself.

As GetSchema is only used as present by the DataSet, you can escape by returning null for this.

public XmlSchema GetSchema()
{
  return null;
}

Next up, we had to write some code to generate the attributes we needed - for this, you can simply use the WriteAttributeString method of the XmlWriter that we're passed to churn out attributes for the one fixed property of our object (Name), and then the elements in the NameValueCollection.

public void WriteXml(XmlWriter w)
{
  w.WriteAttributeString("Name", _name);
  foreach (string key in _attributes.Keys)
  {
    string value = _attributes[key];
    w.WriteAttributeString(key,value);
  }
}

For ReadXml, we simply had to do the reverse - fetching the "Name" attribute, and dumping the rest into our NameValueCollection.

public void ReadXml(XmlReader r)
{
    _attributes = new NameValueCollection();
    _name = r.GetAttribute("Name");
    while (r.MoveToNextAttribute())
        if (r.Name!="Name")
            _attributes.Add(r.Name, r.Value);
    r.Read();
}

And that's it! If you want a fully working example project, just download the attached source code.

James first started writing tutorials on Visual Basic in 1999 whilst starting this website (then known as VB Web). Since then, the site has grown rapidly, and James has written numerous tutorials, articles and reviews on VB, PHP, ASP and C#. In October 2003, James formed the company Developer Fusion Ltd, which owns this website, and also offers various development services. In his spare time, he's a 3rd year undergraduate studying Computer Science in the UK. He's also a Visual Basic MVP.

Comments

  • Very helpfull

    Posted by Stupidumb on 02 Feb 2006

    I've been looking for some example like this for a while now, it's great.

    But I have a question about some error I got.

    Using the normal serialization (without overriding the IXmlSerializable in...