Geeks With Blogs
Marcin Celej blog

For a long time I wanted to serialize complex objects to xml. There is an easy way to serialize almost anything with binary serialization. The xml serialization always was difficult. I especially often need to serialize Type object which fortunatelly is binary serializable (in .NET 2.0) but as always there is a problem when I try to serialize it to xml. I sometimes worked it around by adding another string property (xml serializable) that mirrored the Type property. So xml serializer didn't serialize my real property (which was marked with XmlIgnore) but it serialized the mirror property instead. Ughhh, I don't like the aproach. I used to try to implement IXmlSerializable interface but I always failed. I finally found an article that desribes it clearly. You can find the article here: Enrich Your XML Serialization With Schema Providers In The .NET Framework. Here is a sample extracted and simplified from the article.

There is a Test class that contains only one field named Type which type is Type :). The Test class implements IXmlSerializable interface and a method that returns schema for the class. The important thing is that the method should be static and should be pointed by XmlSchemaProvider attribute set on the class.

[XmlRoot(ElementName = "test_root", DataType = "test_type", Namespace = "http://marcel/Test.xsd", IsNullable = false)]
[XmlSchemaProviderAttribute("GetSchema")]
public class Test : IXmlSerializable
{
  public const string Namespace = "http://marcel/Test.xsd";
  public Type Type;
  XmlSchema IXmlSerializable.GetSchema()
  {
    throw new System.NotImplementedException("The method or operation is not implemented.");
  }

  void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
  {
    reader.ReadStartElement();
    string typeName = reader.ReadElementContentAsString("type", Namespace);
    this.Type = Type.GetType(typeName);
    reader.ReadEndElement();
  }

  void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
  {
    writer.WriteElementString("type", Namespace, this.Type.AssemblyQualifiedName);
  }

  public static XmlSchemaComplexType GetSchema(System.Xml.Schema.XmlSchemaSet xs)
  {
    XmlSerializer schemaSerializer = new XmlSerializer(typeof(XmlSchema));
    XmlSchema schema = (XmlSchema)schemaSerializer.Deserialize(new XmlTextReader("Test.xsd"));
    xs.Add(schema);
    XmlQualifiedName name = new XmlQualifiedName("test_type", Namespace);
    return (XmlSchemaComplexType)schema.SchemaTypes[name];
  }
}

The schema for the test class:

<xs:schema xmlns:tns="http://marcel/Test.xsd" 
  elementFormDefault="qualified" 
  targetNamespace="http://marcel/Troduct.xsd" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="test_root" type="tns:test_type" />
  <xs:complexType name="test_type">
    <xs:sequence>
      <xs:element name="type" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

Here is a sample code that serializes and deserializes a Test object:

Test p = new Test();
p.Type = typeof(string);
XmlSerializer ser = new XmlSerializer(typeof(Test));
StringWriter sw = new StringWriter();
ser.Serialize(sw, p);
string s = sw.ToString();
StringReader sr = new StringReader(s);
Test p1 = (Test)ser.Deserialize(sr);

And finally, here is a xml serialization output:

<?xml version="1.0" encoding="utf-16"?>
<test_root xmlns="http://marcel/Test.xsd">
  <type>System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</type>
</test_root>

The above example is much more complicated than my mirror property but I like to have a choice to do something quick or fancy. I hope the sample does not horrify anybody. By the way: the schema can be generated completely in code but I am horrified with that as it is a little bit tricky.

Posted on Friday, May 19, 2006 6:42 PM | Back to top


Comments on this post: Custom xml serialization in .Net

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © Marcin Celej | Powered by: GeeksWithBlogs.net