Article: XML Serialization 101

Home Page


Consultancy

  • Service Vouchers
  • Escrow Service

Shop



Programming
  • Articles
  • Tools
  • Links

Search

 

Contact

 

PHPinfo


$_SERVER







Using XML and XmlSerializer to persist some data

category 'KB', language C#, created 28-Oct-2010, version V1.0, by Luc Pattyn


Work In Progress

This article isn't finished yet, it is "Work In Progress". It may still change a lot in the near future, it probably still needs clarifications, additions and corrections. It might also be split into more than one article, and/or get a different URL; it might even be removed after all.


License: The author hereby grants you a worldwide, non-exclusive license to use and redistribute the files and the source code in the article in any way you see fit, provided you keep the copyright notice in place; when code modifications are applied, the notice must reflect that. The author retains copyright to the article, you may not republish or otherwise make available the article, in whole or in part, without the prior written consent of the author.

Disclaimer: This work is provided as is, without any express or implied warranties or conditions or guarantees. You, the user, assume all risk in its use. In no event will the author be liable to you on any legal theory for any special, incidental, consequential, punitive or exemplary damages arising out of this license or the use of the work or otherwise.


XML is a vast subject. This article will only scratch the surface; in particular it will illustrate how XML and XmlSerializer can be used for persisting some data.

MSDN references

Some useful links to MSDN:

Reference MaterialClasses
Introducing XML Serialization
XML attributes
XmlSerializer

XmlSerializer

XmlSerializer is the class that deals with XML serialization for serializable data types; these include:

  • most value types, including all kinds of numeric types, and DateTime. Notes:
    • System.DateTime uses a universal format, avoiding all problems with regional settings;
    • System.Drawing.Color is the odd one out: it looses its data without even throwing an Exception.
  • any class or struct that has a parameterless constructor, provided all its public data fields and properties are also serializable;
  • any enumerable collection of such objects, including Arrays and Lists.

When XmlSerializer.Serialize() is called, all public data fields and properties get serialized automatically to a text stream. The data gets converted into strings by calling ToString() and the result gets HTML-escaped, i.e. some conversions get applied to prevent the XML scheme from breaking. As an example [ < & > ] gets replaced by [ &lt; &amp; &gt; ].

Note: the order of class members may be changed; e.g. typically data members get serialized before properties.

The (de)serialization can be inlfuenced by adding attributes, see MSDN on XML attributes. One useful attribute is [XmlIgnore] which excludes the data field from the serialization process.

Example 1

This example shows some value types and the string encoding; it also shows how null references are skipped:

// class to be serialized
public class ValueTypes {
	public int myInt=123;
	public DateTime myDate=DateTime.Now;
	public Color myColor1=Color.FromArgb(0x11, 0x22, 0x33);
	public Color myColor2=Color.Yellow;
	public string myNullString=null;
	public string myString="abc'.!@#$%^&*()<-_=+>qwerty</str>uiop";
	public override string ToString() {
		return "ValueTypes: myInt="+myInt+"  myDate="+myDate+Environment.NewLine+
			"  myColor1="+myColor1+"  myColor2="+myColor2+Environment.NewLine+
			"  myNullString="+myNullString+"  myString="+myString;
		}
}
// serializing code
using (StreamWriter sw=File.CreateText(FILEPATH)) {
	XmlSerializer xSer=new XmlSerializer(typeof(ValueTypes));
	xSer.Serialize(sw, new ValueTypes());
}
<?xml version="1.0" encoding="utf-8"?>
<ValueTypes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <myInt>123</myInt>
  <myDate>2010-10-27T18:53:09.758+02:00</myDate>
  <myColor1 />
  <myColor2 />
  <myString>abc'.!@#$%^&amp;*()&lt;-_=+&gt;qwerty&lt;/str&gt;uiop</myString>
</ValueTypes>
// deserializing code
using (StreamReader sr=File.OpenText(FILEPATH)) {
	XmlSerializer xSer=new XmlSerializer(typeof(ValueTypes));
	ValueTypes vt=(ValueTypes)xSer.Deserialize(sr);
	log(vt.ToString());
}
// result
ValueTypes: myInt=123  myDate=28-Oct-2010 0:40:45
  myColor1=Color [Empty]  myColor2=Color [Empty]
  myNullString=  myString=abc'.!@#$%^&*()<-_=+>qwerty</str>uiop

Example 2

This example demonstrates lists, where each item is an aggregation of two objects; the object hierarchy gets handled completely automatically:

// classes to be serialized
public class Mini {
	public int val;
	private Mini() { }
	public Mini(int val) { this.val=val; }
	public override string ToString() {return "Mini: val="+val;}
}
public class Combo {
	public Mini Mini1;
	public Mini Mini2;
	private Combo() { }
	public Combo(int val1, int val2) { Mini1=new Mini(val1); Mini2=new Mini(val2); }
	public override string ToString() { return "Combo: Mini1.val="+Mini1.val+"   Mini2.val="+Mini2.val; }
}
// serializing code
List<Mini> list=new List<Mini>();
for (int i=0; i<3; i++) list.Add(new Mini(i));
using (StreamWriter sw=File.CreateText(FILEPATH)) {
	XmlSerializer xSer=new XmlSerializer(typeof(List<Mini>));
	xSer.Serialize(sw, list);
}
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfCombo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Combo>
    <Mini1>
      <val>11</val>
    </Mini1>
    <Mini2>
      <val>121</val>
    </Mini2>
  </Combo>
  <Combo>
    <Mini1>
      <val>12</val>
    </Mini1>
    <Mini2>
      <val>144</val>
    </Mini2>
  </Combo>
  <Combo>
    <Mini1>
      <val>13</val>
    </Mini1>
    <Mini2>
      <val>169</val>
    </Mini2>
  </Combo>
</ArrayOfCombo>
// deserializing code
using (StreamReader sr=File.OpenText(FILEPATH)) {
	XmlSerializer xSer=new XmlSerializer(typeof(List<Mini>));
	List<Combo> list=(List<Combo>)xSer.Deserialize(sr);
	foreach (Combo combo in list) log(combo.ToString());
}
// result
Combo: Mini1.val=11   Mini2.val=121
Combo: Mini1.val=12   Mini2.val=144
Combo: Mini1.val=13   Mini2.val=169

Heterogeneous collections

So far the data was very predictable, it was either one object, or one collection of objects, all instances of a single class. When the collection isn't homogeneous, problems arise as the type information of the individual objects isn't serialized. Here is an example that fails:

// classes to be serialized
	public class Base {}

	public class DerivedA : Base {
		public int A=1;
	}

	public class DerivedB : Base {
		public int B=2;
	}
// serializing code
using (StreamWriter sw=File.CreateText(FILEPATH)) {
	List<Base> list=new List<Base>();
	list.Add(new DerivedA());
	list.Add(new DerivedB());
	xSer=new XmlSerializer(typeof(List<Base>));
	xSer.Serialize(sw, list);		// InvalidOperationException
}

The XmlInclude attribute can solve the problem if the derived classes are known to the base class at build time; here is an example. And another XmlSerializer constructor (with "extraTypes") can solve it for dynamic types, e.g. when supporting an add-on scheme.

Conclusion

It works great for single objects, and for homogeneous collections. And it gets harder for more dynamic situations. However it can't handle the Color type at all!

History

  • Version 1.0 (28-Oct-2010): Original version


Perceler

Copyright © 2012, Luc Pattyn

Last Modified 04-May-2025