Xml serialization using generics


Serialize/deserialize your objects using generics. Customize settings like indentation, encoding, namespaces and others.

Table of contents

 

XML Serialization Overview

XML serialization is the process of converting an object into a XML string in order to persist it to memory, a database, or a file. Its main purpose is to save the state of an object in order to be able to recreate it when needed. The reverse process is called deserialization.

Some good uses for XML serialization/deserialization are [1]:

  • Storing user preferences in an object
  • Maintaining security information across pages and applications
  • Modification of XML documents without using the DOM
  • Passing an object from one application to another
  • Passing an object from one domain to another
  • Passing an object through a firewall as an XML string

 

A generic serializer class – XmlSerializer<T>

I’ve created a generic class to serialize/deserialize XML:

XmlSerializer

This class allows us to:

  • Serialize an object to a XML string
  • Deserialize an object from a XML string
  • Serialize an object to a XML file
  • Deserialize an object from a XML file

It’s also possible to customize some settings like indentation, encoding, namespaces and others (see examples below).


 

The scenario – User Shopping Cart

(Disclaimer: this is not intended to reflect a real-world shopping cart model)

XML Serialization - Shopping Cart Model

Model source code (click to expand):

namespace Serialization.Model
{
    [Serializable]
    [XmlRoot("shopping-cart")]
    public class ShoppingCart
    {
        [XmlElement("purchase-date", IsNullable=true)]
        public DateTime? PurchaseDate { get; set; }

        // {property}Specified
        public bool PurchaseDateSpecified
        {
            get { return PurchaseDate.HasValue; }
        }

        // for each subclass of ShoppingItem you need
        // to specify the correspondent XML element to generate
        [XmlArrayItem("cd", typeof(CD))]
        [XmlArrayItem("book", typeof(Book))]
        [XmlArrayItem("dvd", typeof(Dvd))]
        [XmlArray("items")]
        public List Items { get; set; }

        [XmlIgnore]
        public double TotalPrice
        {
            get
            {
                double total = 0;

                foreach (ShoppingItem i in Items)
                    total += i.Price;

                return total;
            }
        }

        public ShoppingCart()
        {
            Items = new List();
        }
    }

    [Serializable]
    [XmlRoot("item")]
    public class ShoppingItem
    {
        [XmlAttribute("reference")]
        public string Reference { get; set; }

        [XmlAttribute("price")]
        public double Price { get; set; }

        public ShoppingItem()
        {
        }
    }

    [Serializable]
    [XmlRoot("book")]
    public class Book : ShoppingItem
    {
        [XmlElement("name")]
        public string Name { get; set; }

        [XmlElement("author")]
        public string Author { get; set; }

        [XmlElement("description")]
        public string Description { get; set; }

        public Book()
        {
        }
    }

    [Serializable]
    [XmlRoot("cd")]
    public class CD : ShoppingItem
    {
        [XmlElement("artist")]
        public string Artist  { get; set; }

        [XmlElement("name")]
        public string Name { get; set; }

        [XmlElement("genre")]
        public string Genre { get; set; }

        public CD()
        {
        }
    }

    [Serializable]
    [XmlRoot("dvd")]
    public class Dvd : ShoppingItem
    {
        [XmlElement("name")]
        public string Name { get; set; }

        [XmlElement("genre")]
        public string Genre { get; set; }

        public Dvd()
        {
        }
    }

    [Serializable]
    [XmlRoot("user")]
    public class User
    {
        [XmlAttribute("id")]
        public int Id { get; set; }

        [XmlAttribute("user-type")]
        public UserType Type { get; set; }

        [XmlElement("first-name")]
        public string FirstName { get; set; }

        [XmlElement("last-name")]
        public string LastName { get; set; }

        [XmlIgnore]
        public string FullName
        {
            get
            {
                if (string.IsNullOrEmpty(FirstName))
                    return LastName;

                if (string.IsNullOrEmpty(LastName))
                    return FirstName;

                return string.Format("{0} {1}", FirstName, LastName);
            }
        }

        [XmlElement("age")]
        public int? Age { get; set; }

        [XmlElement("email")]
        public string Email { get; set; }

        public bool AgeSpecified
        {
            get { return Age.HasValue; }
        }

        [XmlElement("address")]
        public Address UserAddress { get; set; }

        [XmlElement("delivery-address")]
        public Address DeliveryAddress { get; set; }

        [XmlElement("cart")]
        public ShoppingCart ShoppingCart { get; set; }

        public User()
        {
        }
    }

    [Serializable]
    [XmlRoot("address")]
    public class Address
    {
        [XmlElement("street")]
        public string Street { get; set; }

        [XmlElement("postal-code")]
        public string PostalCode { get; set; }

        [XmlElement("city")]
        public string City { get; set; }

        [XmlElement("country")]
        public string Country { get; set; }

        [XmlIgnore]
        public string FullAddress
        {
            get
            {
                return string.Format("{0}{1}{2} {3}{1}{4}",
                     Street, System.Environment.NewLine, PostalCode, City, Country);
            }
        }

        public Address()
        {
        }
    }

    [Flags]
    public enum UserType
    {
        [XmlEnum("0")]
        Basic = 0,

        [XmlEnum("1")]
        Premium = 1,

        [XmlEnum("2")]
        Platinum = 2
    }
}

 

Using the code

Create an user, serialize it into a string and recreate the object from the string

static void Main(string[] args)
{
    User user = CreateUser();

    // default serialization settings
    string xml = XmlSerializer<User>.Serialize(user);

    // get user from XML
    User user2 = XmlSerializer<User>.Deserialize(xml);
}

private static User CreateUser()
{
    User user = new User();
    user.Age = 20;
    user.Type = UserType.Platinum;
    user.FirstName = "Rui";
    user.LastName = "Jarimba";
    user.Email = "email@somewhere.com";

    user.UserAddress = new Address();
    user.UserAddress.Street = "my street 1";
    user.UserAddress.PostalCode = "1000-001";
    user.UserAddress.City = "Lisbon";
    user.UserAddress.Country = "Portugal";

    user.DeliveryAddress = new Address();
    user.DeliveryAddress.Street = "another street";
    user.DeliveryAddress.PostalCode = "1000-002";
    user.DeliveryAddress.City = "Lisbon";
    user.DeliveryAddress.Country = "Portugal";

    //
    // Shopping cart
    //
    user.ShoppingCart = new ShoppingCart();
    // u.ShoppingCart.PurchaseDate = DateTime.Now;

    Book book1 = new Book();
    book1.Name = "Jamie's Italy";
    book1.Price = 34.95;
    book1.Reference = "978-1401301958";
    book1.Author = "Jamie Oliver";
    book1.Description = "Italian food made by Jamie Oliver!";
    user.ShoppingCart.Items.Add(book1);

    Book book2 = new Book();
    book2.Name = "Ensaio Sobre a Cegueira";
    book2.Price = 59.95;
    book2.Reference = "B0042TL15I";
    book2.Author = "José Saramago";
    user.ShoppingCart.Items.Add(book2);

    CD cd = new CD();
    cd.Name = "The Blackening";
    cd.Artist = "Machine Head";
    cd.Genre = "Trash Metal";
    cd.Price = 15.0;
    cd.Reference = "B000N3ST9I";
    user.ShoppingCart.Items.Add(cd);

    Dvd dvd = new Dvd();
    dvd.Name = "The Lord of the Rings: The Return of the King";
    dvd.Price = 14.99;
    dvd.Reference = "B00005JKZY";
    dvd.Genre = "Action, Adventure, Drama ";
    user.ShoppingCart.Items.Add(dvd);

    return user;
}

Generated XML (click to expand):

<?xml version="1.0" encoding="utf-8"?>
<user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="1" user-type="2">
    <first-name>Rui</first-name>
    <last-name>Jarimba</last-name>
    <age>30</age>
    <email>email@somewhere.com</email>
    <address>
        <street>my street 1</street>
        <postal-code>1000-001</postal-code>
        <city>Lisbon</city>
        <country>Portugal</country>
    </address>
    <delivery-address>
        <street>another street</street>
        <postal-code>1000-002</postal-code>
        <city>Lisbon</city>
        <country>Portugal</country>
    </delivery-address>
    <cart>
        <items>
            <book reference="978-1401301958" price="34.95">
                <name>Jamie's Italy</name>
                <author>Jamie Oliver</author>
                <description>Italian food made by Jamie Oliver!</description>
            </book>
            <book reference="B0042TL15I" price="59.95">
                <name>Ensaio Sobre a Cegueira</name>
                <author>José Saramago</author>
            </book>
            <cd reference="B000N3ST9I" price="15">
                <artist>Machine Head</artist>
                <name>The Blackening</name>
                <genre>Trash Metal</genre>
            </cd>
            <dvd reference="B00005JKZY" price="14.99">
                <name>The Lord of the Rings: The Return of the King</name>
                <genre>Action, Adventure, Drama </genre>
            </dvd>
        </items>
    </cart>
</user>

 

Using the XmlSerializer settings

You can control other settings like indentation, namespaces, encoding and others using the classes XmlWritterSettings, XmlReaderSettings and XmlSerializerNamespaces.
 

Example 1: Remove XML indentation

User user = CreateUser();

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = false;

string xml = XmlSerializer<User>.Serialize(user, settings);

// get user from XML
User user2 = XmlSerializer<User>.Deserialize(xml);

Output XML

<?xml version="1.0" encoding="utf-8"?><user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="1" user-type="2"><first-name>Rui</first-name><last-name>Jarimba</last-name><age>30</age><email>email@somewhere.com</email><address><street>my street 1</street><postal-code>1000-001</postal-code><city>Lisbon</city><country>Portugal</country></address><delivery-address><street>another street</street><postal-code>1000-002</postal-code><city>Lisbon</city><country>Portugal</country></delivery-address><cart><items><book reference="978-1401301958" price="34.95"><name>Jamie's Italy</name><author>Jamie Oliver</author><description>Italian food made by Jamie Oliver!</description></book><book reference="B0042TL15I" price="59.95"><name>Ensaio Sobre a Cegueira</name><author>José Saramago</author></book><cd reference="B000N3ST9I" price="15"><artist>Machine Head</artist><name>The Blackening</name><genre>Trash Metal</genre></cd><dvd reference="B00005JKZY" price="14.99"><name>The Lord of the Rings: The Return of the King</name><genre>Action, Adventure, Drama </genre></dvd></items></cart></user>

 

Example 2: Remove namespaces

User user = CreateUser();

XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "");

string xml = XmlSerializer<User>.Serialize(user, namespaces);

// get user from XML
User user2 = XmlSerializer<User>.Deserialize(xml);

Output XML(click to expand):

<?xml version="1.0" encoding="utf-8"?>
<user id="1" user-type="2">
    <!-- Code omitted for brevity -->
</user>

 

Example 3: Add custom namespaces

User user = CreateUser();

XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("n1", "http://mynamespace1.com");
namespaces.Add("n2", "http://mynamespace2.com");

string xml = XmlSerializer<User>.Serialize(user, namespaces);

// get user from XML
User user2 = XmlSerializer<User>.Deserialize(xml);

Output XML(click to expand):

<?xml version="1.0" encoding="utf-8"?>
<user xmlns:n1="http://mynamespace1.com" xmlns:n2="http://mynamespace2.com" id="1" user-type="2">
    <!-- Code omitted for brevity -->
</user>

 

Example 4: Specify encoding

User user = CreateUser();

XmlWriterSettings writterSettings = new XmlWriterSettings();
writterSettings.Encoding = Encoding.UTF32;

string xml = XmlSerializer<User>.Serialize(user, writterSettings);

// get user from XML
User user2 = XmlSerializer<User>.Deserialize(xml, Encoding.UTF32);

 

Example 5: Remove XML declaration

User user = CreateUser();

XmlWriterSettings writterSettings = new XmlWriterSettings();
writterSettings.OmitXmlDeclaration = true;

string xml = XmlSerializer<User>.Serialize(user, writterSettings);

XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.ConformanceLevel = ConformanceLevel.Fragment;
User user2 = XmlSerializer<User>.Deserialize(xml, readerSettings);
User user3 = XmlSerializer<User>.Deserialize(xml); // this works too

Output XML(click to expand):

<user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="1" user-type="2">
    <!-- Code omitted for brevity -->
</user>

 

Example 6: File serialization

User user = CreateUser();
string filename = @"c:\dump\user.xml";

// default file serialization
XmlSerializer<User>.SerializeToFile(user, filename);

// try to get the object from the created file
User u3 = XmlSerializer<User>.DeserializeFromFile(filename);

//
// define some settings
//
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "");

XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
settings.IndentChars = "\t";

XmlSerializer<User>.SerializeToFile(user, filename, namespaces, settings);
u3 = XmlSerializer<User>.DeserializeFromFile(filename);

 

References

[1] XML Serialization Using C# (DotNetJohn)
http://www.dotnetjohn.com/articles.aspx?articleid=173

[2] Controlling XML Serialization Using Attributes (MSDN)
http://msdn.microsoft.com/en-us/library/2baksw0z%28v=vs.80%29.aspx

[3] XML Serialization Articles (BlackWasp)
http://www.blackwasp.co.uk/XMLArticles.aspx
 

Downloads

Download the XmlSerializer class: XmlSerializer.cs

Download the demo project: Xml Serialization Demo

Technorati Tag: , , , ,


About these ads

8 thoughts on “Xml serialization using generics

  1. Pingback: Entity Framework and T4: Generate Specification Objects for your entities | Rui Jarimba

  2. Pingback: Entity Framework and T4: Generate Query Objects on the fly, part 1 | Rui Jarimba

  3. Pingback: DotNetShoutout

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s