Click here to Skip to main content
15,860,859 members
Articles / Programming Languages / XML

XML Serialization Using Generics

Rate me:
Please Sign up or sign in to vote.
5.00/5 (29 votes)
3 Apr 2012CPOL2 min read 128.9K   1.4K   97   31
Serialize/deserialize your objects using generics. Customize settings like indentation, encoding, namespaces and others

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 an XML string
  • Serialize an object to an XML file
  • Deserialize an object from an 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:

C#
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<ShoppingItem> 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 a user, serialize it into a string and recreate the object from the string.

C#
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:

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>

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

C#
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
<?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

C#
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:

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

Example 3: Add Custom Namespaces

C#
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:

XML
<?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

C#
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

C#
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:

XML
<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

C#
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Italy Italy
My name is Rui Jarimba and I was born in Madeira island, Portugal and I currently live in Rome, Italy.

I have more than 10 years of experience developing software using the .NET Framework and other technologies (Web development, Databases, ...).

Some of my professional interests are: software development best practices, software architecture, cloud computing, Continuous Integration (CI), Continuous Delivery (CD) and agile methodologies such as Scrum, Kanban, Lean and any other methodology that can help me to become a better and more productive software engineer.

I believe in good code - code that is readable, maintainable, reusable, testable and deployable. This means that I'm not the "quick and dirty" type, I write code for the medium/long term whenever possible.

Something else about me - I love music, I am an amateur photographer, not a big fan of gyms (I prefer to do some outdoor activity such as walking/hiking), big foodie (I love Mediterranean cuisine and my glass of wine!).

Comments and Discussions

 
QuestionNot able to download source from this site Pin
twoheadedboy8522-Apr-19 15:59
twoheadedboy8522-Apr-19 15:59 
GeneralMy vote of 4 Pin
Member 374993810-Oct-13 1:46
Member 374993810-Oct-13 1:46 
GeneralRe: My vote of 4 Pin
Rui Jarimba10-Oct-13 2:14
professionalRui Jarimba10-Oct-13 2:14 
GeneralRe: My vote of 4 Pin
Member 374993810-Oct-13 7:01
Member 374993810-Oct-13 7:01 
GeneralMy vote of 5 Pin
Leonardo Paneque9-May-12 6:43
Leonardo Paneque9-May-12 6:43 
GeneralRe: My vote of 5 Pin
Rui Jarimba18-Jul-12 8:26
professionalRui Jarimba18-Jul-12 8:26 
QuestionTrouble w/Code Download Pin
Jeff Bowman2-Apr-12 13:13
professionalJeff Bowman2-Apr-12 13:13 
AnswerRe: Trouble w/Code Download Pin
Rui Jarimba2-Apr-12 21:33
professionalRui Jarimba2-Apr-12 21:33 
AnswerRe: Trouble w/Code Download Pin
Rui Jarimba3-Apr-12 5:48
professionalRui Jarimba3-Apr-12 5:48 
GeneralRe: Trouble w/Code Download Pin
Jeff Bowman3-Apr-12 20:34
professionalJeff Bowman3-Apr-12 20:34 
GeneralRe: Trouble w/Code Download Pin
Rui Jarimba3-Apr-12 21:08
professionalRui Jarimba3-Apr-12 21:08 
GeneralRe: Trouble w/Code Download Pin
Thyri22-May-17 13:59
Thyri22-May-17 13:59 
GeneralGreat Article! Pin
raananv10-Mar-12 8:55
raananv10-Mar-12 8:55 
GeneralRe: Great Article! Pin
Rui Jarimba10-Mar-12 8:59
professionalRui Jarimba10-Mar-12 8:59 
Question5 Point out of 5 Pin
RichardJacksonJr5-Mar-12 18:04
RichardJacksonJr5-Mar-12 18:04 
AnswerRe: 5 Point out of 5 Pin
Rui Jarimba5-Mar-12 21:08
professionalRui Jarimba5-Mar-12 21:08 
GeneralMy vote of 5 Pin
Sujith S Mysore17-Oct-11 17:53
Sujith S Mysore17-Oct-11 17:53 
GeneralRe: My vote of 5 Pin
Rui Jarimba18-Oct-11 12:28
professionalRui Jarimba18-Oct-11 12:28 
QuestionNice article! Pin
Sérgio Vicente17-Oct-11 10:41
Sérgio Vicente17-Oct-11 10:41 
Hi Rui,

I liked your article but I think some points about it should be mentioned:

1. You should specify along the article that the underlying serializer that you use is the XmlSerializer and explain why you opted for this specific serializer.

2. You should have explained the design option of setting the class as a generic class. Why not just generic methods? Using only generic methods, you can also omit the type argument and the compiler will infer it (shorter and easier to read code).

3. Adding the file support was a nice addition. You could also have added the binary support.


Like I said, I liked your article and looking at your code I have found that it is correct, tidy and documented. Well done, you have my 'Excellent' vote.

Kind regards,

Sérgio Vicente.
AnswerRe: Nice article! Pin
Rui Jarimba17-Oct-11 11:26
professionalRui Jarimba17-Oct-11 11:26 
AnswerRe: Nice article! Pin
Rui Jarimba17-Oct-11 13:25
professionalRui Jarimba17-Oct-11 13:25 
QuestionGreat Job! Pin
cubski8-Aug-11 15:48
cubski8-Aug-11 15:48 
AnswerRe: Great Job! Pin
Rui Jarimba8-Aug-11 21:02
professionalRui Jarimba8-Aug-11 21:02 
Questionutf-8 in SQL Server XML data type Pin
Clinton Gallagher8-Aug-11 15:20
professionalClinton Gallagher8-Aug-11 15:20 
AnswerRe: utf-8 in SQL Server XML data type Pin
Rui Jarimba8-Aug-11 21:58
professionalRui Jarimba8-Aug-11 21:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.