Serializing objects to XML and back again in C# is trivial until you need greater control over the operation. How do you serialize binary data, Color properties or some object type that hasn't been invented yet? Implementing IXmlSerializable allows you to read and write object data in whatever format and by any means you choose.
The example serializes a list of objects with a single Color property.
<?xml version="1.0" ?> <Items> <Item>Red</Item> <Item>White</Item> <Item>Blue</Item> </Items>
using System;using System.Collections.Generic;using System.Text;using System.IO;using System.Xml;using System.Xml.Serialization;using System.Drawing; namespace SerializeGenerics1{ public class MyObject { public MyObject(Color MyColor) { _myColor = MyColor; } private Color _myColor; public Color MyColor { get { return _myColor; } set { _myColor = value; } } } public class MyObjectList { List<MyObject> _items = new List<MyObject>(); public List<MyObject> Items { get { return _items; } set { _items = value; } }#region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(System.Xml.XmlReader reader) { _items.Clear(); while (!reader.EOF) { if (reader.ReadToFollowing("Item")) _items.Add(new MyObject(Color.FromName(reader.ReadString()))); } reader.Close(); } public void WriteXml(System.Xml.XmlWriter writer) { writer.WriteStartDocument(); writer.WriteStartElement("Items"); foreach (MyObject myObject in _items) { if (myObject.MyColor.IsKnownColor) writer.WriteElementString("Item", myObject.MyColor.Name); } writer.WriteEndElement(); // close Items tag writer.WriteEndDocument(); writer.Close(); }#endregion}class Program{ static void Main(string[] args) { MyObjectList myObjectList = new MyObjectList(); XmlTextReader reader = new XmlTextReader("MyObjects.xml"); myObjectList.ReadXml(reader); myObjectList.Items.Clear(); myObjectList.Items.Add(new MyObject(Color.BlanchedAlmond)); myObjectList.Items.Add(new MyObject(Color.Blue)); myObjectList.Items.Add(new MyObject(Color.LightSlateGray)); XmlTextWriter writer = new XmlTextWriter("MyObjects.xml", null); writer.Formatting = Formatting.Indented; myObjectList.WriteXml(writer); } }}
This next example serializes settings for a "Wheel of Fortune" style game written in WPF. The "Color" referenced here is from the Systems.Windows.Media namespace and doesn't have a "Name" property as in the previous example. The xml file is nested with a Settings/Setting/<properties> structure:
<?xml version="1.0" ?> <Settings> <Setting> <Percentage>10</Percentage> <Color>#FFFF0000</Color> <Title>Nice Try</Title> <Description /> <IsWinner>False</IsWinner> </Setting> <Setting> <Percentage>10</Percentage> <Color>#FFB0E0E6</Color> <Title>T Shirt</Title> <Description>T-Shirt</Description> <IsWinner>True</IsWinner> </Setting></Settings>
The IXmlSerializable implementation:
using System;using System.Collections;using System.Collections.Generic;using System.Text;using System.IO;using System.Xml;using System.Xml.Serialization;using System.Collections.ObjectModel;using System.Windows.Media;using System.ComponentModel;using System.Diagnostics; namespace Falafel.Training.WPF{ public class Settings : IXmlSerializable, IEnumerable { List<Setting> _items = new List<Setting>(); public void Add(Setting setting) { _items.Add(setting); }#region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(System.Xml.XmlReader reader) { try { XmlTextReader textReader = reader as XmlTextReader; textReader.WhitespaceHandling = WhitespaceHandling.None; _items.Clear(); while (textReader.ReadToFollowing("Setting")) { Setting setting = new Setting(); textReader.Read(); setting.Percentage = Convert.ToInt32(textReader.ReadString()); textReader.Read(); setting.Color = (Color)TypeDescriptor.GetConverter(typeof(Color)).ConvertFromString(textReader.ReadString()); textReader.Read(); setting.Title = textReader.ReadString(); textReader.Read(); setting.Description = textReader.ReadString(); textReader.Read(); setting.IsWinner = Convert.ToBoolean(textReader.ReadString()); _items.Add(setting); } } catch (Exception ex) { throw new ApplicationException("Unable to open Settings file. " + ex.Message); } finally { reader.Close(); }}public void WriteXml(System.Xml.XmlWriter writer){ XmlTextWriter textWriter = writer as XmlTextWriter; textWriter.Formatting = Formatting.Indented; textWriter.WriteStartDocument(); textWriter.WriteStartElement("Settings"); foreach (Setting setting in _items) { string color = TypeDescriptor.GetConverter(typeof(Color)).ConvertToString(setting.Color); textWriter.WriteStartElement("Setting"); textWriter.WriteElementString("Percentage", setting.Percentage.ToString()); textWriter.WriteElementString("Color", color); textWriter.WriteElementString("Title", setting.Title); textWriter.WriteElementString("Description", setting.Description); textWriter.WriteElementString("IsWinner", setting.IsWinner.ToString()); textWriter.WriteEndElement(); // close Setting tag } textWriter.WriteEndElement(); // close Settings tag textWriter.WriteEndDocument(); textWriter.Close();}#endregion#region IEnumerable Members public IEnumerator GetEnumerator() { return _items.GetEnumerator(); }#endregion }}
ReadXML() casts XMLReader to a XMLTextReader to consume the WhiteSpaceHandling property. Likewise, WriteXML casts XMLWriter to XMLTextWriter to use the Formatting property. The structure used here of Settings/Setting/<some properties> is entirely arbitrary. You can read and write to and from any xml structure you care to put together.
Remember Me
a@href@title, i, strike, u
Copyright © 2003-2008 Falafel Software Inc.
Subscribe to Falafel Blogs
The opinions expressed herein are Falafel's employees own personal opinions and do not represent Falafel Software's view in any way in case they go bananas!