Click here to Skip to main content
Click here to Skip to main content

XML serialization using Generics

By , 3 Apr 2012
 

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:

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

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

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

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

<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

License

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

About the Author

Rui Jarimba
Software Developer (Senior)
Ireland Ireland
Member
My name is Rui Jarimba and I was born in Madeira island, Portugal and I currently live in Dublin, Ireland.
 
I’m working as a .NET software developer since 2005.
 
Some of my professional interests are:
 
Web development using .NET Framework;
Service Oriented Architecture (SOA);
Database development and modelling;
Web accessibility, usability, and standards;
Software Architecture;
Design Patterns

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberLeonardo Paneque9 May '12 - 6:43 
good one. Smile | :)
GeneralRe: My vote of 5memberRui Jarimba18 Jul '12 - 8:26 
Thanks Leonardo
QuestionTrouble w/Code DownloadmemberJeff Bowman2 Apr '12 - 13:13 
I'm having some trouble downloading the code--clicking the download link produces only a blank page.
 
Is anyone else seeing this?
AnswerRe: Trouble w/Code DownloadmemberRui Jarimba2 Apr '12 - 21:33 
Hi Jeff,
 
I have fixed the download link. This change is still waiting for approval, but it should be available soon.
 

Regards,
Rui
AnswerRe: Trouble w/Code DownloadmemberRui Jarimba3 Apr '12 - 5:48 
Hi Jeff,
 
The code is now available.
 
Rui
GeneralRe: Trouble w/Code DownloadmemberJeff Bowman3 Apr '12 - 20:34 
Very good, thank you.
 
And thank you for continuing to check in on it even after you'd submitted the fix.
GeneralRe: Trouble w/Code DownloadmemberRui Jarimba3 Apr '12 - 21:08 
No prob Smile | :)
 
Take care
GeneralGreat Article!memberraananv10 Mar '12 - 8:55 
Tx
Laugh | :laugh:
GeneralRe: Great Article!memberRui Jarimba10 Mar '12 - 8:59 
Thanks raananv
Question5 Point out of 5memberdenezt5 Mar '12 - 18:04 
Very nice article...<great!>
AnswerRe: 5 Point out of 5memberRui Jarimba5 Mar '12 - 21:08 
Thanks denezt
GeneralMy vote of 5memberSujith S Mysore17 Oct '11 - 17:53 
Good Article, very clean!
GeneralRe: My vote of 5memberruijarimba18 Oct '11 - 12:28 
Thanks Sujith
QuestionNice article!memberSé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!memberruijarimba17 Oct '11 - 11:26 
Hi Sérgio,

Thank you for your vote and for your comment.
 

Sérgio Vicente wrote:
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.

Yes, it uses System.Xml.XmlSerializer, my idea was to create a generic class to ease this operations. With only 1 line of code you can serialize/deserialize XML to/from a string or file, without worrying about casts and other details. To be honest, I saw some generic classes but those were somehow limited. I decided to create a generic class that was more flexible, and allowed us to easily customize other settings such as indentation, namespaces and others.
 

Sérgio Vicente wrote:
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).

It seemed more natural to create the class as generic, and not the methods. I guess it's just a matter of style, some will prefer to create a generic class, others like you will prefer to create generic methods. To be honest I don't know if there are any guidelines for this. It doesn't bother me at all writing the type argument, in this particular case is more readable (IMO):
 
string xml = XmlSerializer<User>.Serialize(user)
 

Sérgio Vicente wrote:
3. Adding the file support was a nice addition. You could also have added the binary support.

This was a class for XML serialization/deserialization, it doesn't make sense to include binary support here. It would be better to create a separate class for binary serialization/deserialization.
 

Best regards,
Rui
AnswerRe: Nice article!memberruijarimba17 Oct '11 - 13:25 
I forgot to mention:
One of the reasons for creating the article was also to show how to customize the generated XML, using the attributes
 
Best regards,
Rui
QuestionGreat Job!membercubski8 Aug '11 - 15:48 
Nice and informative article.
AnswerRe: Great Job!memberruijarimba8 Aug '11 - 21:02 
Thanks cubski
Questionutf-8 in SQL Server XML data typememberclintonG8 Aug '11 - 15:20 
I an frustrated with trying to learn to write XML to a table in MS-SQLServer 2005 as it apparently wants utf-16 (which to my way of thinking is Microsoft's insanity as all XML I see on the web is encoded as utf-8). If authors or readers of this article have any advice or strategy to write RSS to MS-SQLServer 2005 I am all ears...
clintonG

AnswerRe: utf-8 in SQL Server XML data typememberruijarimba8 Aug '11 - 21:58 
Hi clintonG,
 
See if this helps:
 
http://www.linglom.com/2008/08/26/create-dynamic-rss-feed-from-ms-sql-server-using-aspnet-part-i-vbnet/[^]
 
C# version:
http://www.linglom.com/2008/09/01/create-dynamic-rss-feed-from-ms-sql-server-using-aspnet-part-ii-c/[^]
 
Rui
GeneralRe: utf-8 in SQL Server XML data typememberclintonG9 Aug '11 - 4:55 
Thanks Rui I'll try that 2005 project in 2010 because I never saw easier code than that use of a SqlDataReader to save XML into a SQLServer2005 table.
 
In the meantime here's some observations:
 
A.) The feed loaded from http://www.feedforall.com/sample.xml uses encoding="windows-1252" It's my understanding SQL Server XML Datatype expects utf-16. Any comments about the encoding issues as they pertain to saving in SQLServer and any as they may pertain to validation and user agent parsing of RSS XML encoded as windows-1252?
 
B.) You don't show us your sproc. Here is one I am working on. Any comments to improve it would be welcomed (like is it smart to use an out variable and reuse the same sproc for both saving the feed and also retrieving it later?):
 
ALTER PROCEDURE [dbo].[msp_Xml_SaveRssChannel] 
	-- Required parameters passed from calling page
	@UserId             uniqueidentifier,
	@RssChannelXml      xml
 
-- AS keyword indicates code is about to start
AS
 
BEGIN TRY	
    BEGIN TRANSACTION 		
        INSERT INTO dbo.RssChannels (UserId, RssChannelXml)
        VALUES (@UserId, @RssChannelXml)
    COMMIT TRANSACTION 	
END TRY	
 
BEGIN CATCH
	EXECUTE msp_Database_GetErrorInfo      
END CATCH
 
ALTER PROCEDURE [dbo].[msp_Database_GetErrorInfo] 
AS
BEGIN
 
  SET NOCOUNT ON;
 
  SELECT ERROR_NUMBER() AS ErrorNumber,
	 ERROR_SEVERITY() AS ErrorSeverity,
	 ERROR_STATE() AS ErrorState,
	 ERROR_PROCEDURE() AS ErrorProcedure,
	 ERROR_LINE() AS ErrorLine,
	 ERROR_MESSAGE() AS ErrorMessage;			 
END
 
C.) Can we use the above to serialize the feed XML and save it in the table and what is the benefit of serializing in this context as opposed to using a SqlDataReader? with sproc?
clintonG

GeneralRe: utf-8 in SQL Server XML data typememberruijarimba9 Aug '11 - 5:06 
Hi clintonG,
 
My article is about XML Serialization in .NET, not SQL Server.
To be honest I never used SQL Server XML datatype, I found those links in Google and then I've posted it here, hoping that it could help you.
 
Rui
Questiongood job donememberyounkarm_chung2 Aug '11 - 10:54 
good job done
AnswerRe: good job donememberruijarimba2 Aug '11 - 10:58 
Thanks younkarm_chung!
GeneralMy vote of 5membersund7wells1 Aug '11 - 21:49 
good one

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 3 Apr 2012
Article Copyright 2011 by Rui Jarimba
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid