Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Generic XML Serialization Methods

0.00/5 (No votes)
29 Apr 2009 1  
An XML Helper Class that can Serialize and De-Serialize custom User objects using C# Generics

Introduction 

My search for an XML Wrapper to serialize and de-serialize my objects was fruitless. Apparently the internet has little that can do this, unless you want to use a complete Object state management solution like Karvonite which as with any external solution will come with its overheads, bugs, and what not.

What I was looking for was intuitively simple, an XML Save | Load method that I could re-use, for any object type. Andrew Ma from Devhood, wrote an article that solved the problem, for a specified object type.

However it does not take into account the following:

  1. Ability to automatically name XML file based on the type of the object. This avoids the programmer from having to map his XML file names to the object he’s trying to serialize.
  2. The ability to pass in any object to the XML methods to serialize and de-serialize without worrying about its type (provided of course if the object is serializable, if all of its fields that are to be serialized are marked with appropriate XMLAttribute such as  [XmlAttribute("Password")] for a class variable of name “password”. Refer to Figure 1.)

    Correctly Serialized Class with XML Attributes

    Figure 1: Correctly Serialized Class (with XmlAttribute)

  3. To persist state of the XmlSerializer (Namespace: System.Xml.Serialization) without having to re-initialize it for the Serialize or De-Serialize methods. 

In order to achieve the above objectives, I utilized a C# feature called Generics to provide Type independency, in order to utilize my XML Helper class for any serializable object, in any C# application.

Background 

Using the Code  

To run the code, you will need Visual Studio 2008 Express. All the corresponding imports and references have been made.  

Test Class (To be Serialized into XML)

The main class file I used to test is called UserList which includes primarily a System.Collection.ArrayList of a class of Users which include in turn a bunch of primitive C# data types.

This is a good example to test the automatic serialization of what is arguably a complex data structure / class.

// UserList.cs 

using System;
using System.Collections;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace TESTXML
{
    // Shopping list class which will be serialized
    [XmlRoot("UserList")]
    public class UserList
    {
        private ArrayList myUserList;

        public UserList()
        {
            myUserList = new ArrayList();
        }              

        [XmlElement("myUsers")]
        public User[] myUsers
        {
            get
            {
                User[] myUsers = new User[myUserList.Count];
                myUserList.CopyTo(myUsers);
                return myUsers;
            }
            set
            {
                if (value == null) 
                    return;
                User[] myUsers = (User[])value;
                myUserList.Clear();
                foreach (User myUser in myUsers)
                    myUserList.Add(myUser);
            }
        }

        public string AddItem(User myUser)
        {
            myUserList.Add(myUser);
            return myUser.ToString();
        }
    }
}		

Test Sub Class (To Also Be Automatically Serialized into XML)

//User.cs 

public class User
{
    [XmlAttribute("UserName")]
    public String UserName = "";

    [XmlAttribute("Email")]
    public String Email = "";

    [XmlAttribute("Password")]
    public String Password = "";

    [XmlAttribute("TotalScore")]
    public int TotalScore = 0;

    [XmlAttribute("IsApproved")]
    public Boolean IsApproved = false;

    public User(string myUserName, String myEmail, String myPassword, 
				int myTotalScore, Boolean myIsApproved)
    {
        UserName = myUserName;
        Email = myEmail;
        Password = myPassword;
        TotalScore = myTotalScore;
        IsApproved = myIsApproved;
    }

    public override string ToString()
    {
        return "UserName: " + UserName + ", Email: " + Email + ", 
		TotalScore = " + TotalScore + ", IsApproved = " + IsApproved;
    }
} 

Main XML Helper Class that Serializes | Deserializes Any Serializable Object of Any Class Passed to it

//Main File: XMLHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;

namespace TESTXML
{
   public class XMLHelper <T>
    {
       XmlSerializer mySerializer ;
       String ClassName;
       String BaseDirectory;
       
       public XMLHelper()
       {
           mySerializer = new XmlSerializer(typeof(T));
           BaseDirectory = "";
       }

       public XMLHelper(String myBaseDirectory)
       {
           mySerializer = new XmlSerializer(typeof(T));
           BaseDirectory = myBaseDirectory;
       }

       public String FileName(T myObj)
       {
           ClassName = myObj.GetType().Name;
           return BaseDirectory + @"\" + ClassName + ".xml";           
       }

       public void Save(T myObj)
        {
            TextWriter myWriter = new StreamWriter(FileName(myObj));
            mySerializer.Serialize(myWriter, myObj);
            myWriter.Close();
        }

        public T Load(T myObj)
        {
            XmlSerializer mySerializer = new XmlSerializer(typeof(T));
            TextReader myReader = new StreamReader(FileName(myObj));
            T NewObject = (T)mySerializer.Deserialize(myReader);
            myReader.Close();
            return NewObject;
        }        
    }
}

Points of Interest

public String FileName(T myObj)
{
    ClassName = myObj.GetType().Name;
    return BaseDirectory + "\\" + ClassName + ".xml";           
}

Note in the above, how I extracted the Object File Name, using the GetType method, and a conceptual Reflection concept to generate automatically an ***.xml file name for the corresponding object, in the appropriate Base Directory.

This increases the level of re-usability by one, while decreasing one more thing a programmer needs to take care of, i.e. naming convention with which to map XML file names on disk to user objects. A neat little tweak.  

Using the Code

Initialize the BaseDirectory to your XML file Path Location respect to the Project Default Output directory. 

Instantiate a new XMLHelper class with the Type of the object to be invoked, in this case just the class name.

At any point later, reload the same from the XMLHelper class. (Note: The XMLHelper class can be re-instantiated, all you would need is the base directory, which should eventually be made a project setting anyway.)

UserList myListOfUsers = new UserList();     
String BaseDirectory = "Data/XML"
XMLHelper<UserList>myXMLHelper = new XMLHelper<UserList>(BaseDirectory);
myListOfUsers = null;
//Load From BaseDirectory
myListOfUsers = (UserList)myXMLHelper.Load(myListOfUsers);

Results  

Create / Load Test object initializes UserList with two Users In it

Serialize object serializes the just created UserList object into XML and writes it to Disk, while resetting the object.

De-Serialize object gets the FilePath of the object (by simply accepting as an argument the Object type as shown above in the FileName function), reads it from disk and into memory thereby repopulating the object of class UserList.

The process is complete.

Figure 2: Successful Test of Serialization De-Serialization of UserList Class

You can download the accompanying source code and all files from the link at the top of this article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here