5,442,164 members and growing! (16,641 online)
Email Password   helpLost your password?
Languages » C# » General     Intermediate License: The Code Project Open License (CPOL)

XML serialization for complex object model

By brent.wjh

handles object graphs and circular references in XML serialization
C# (C# 1.0, C# 2.0, C# 3.0, C#), .NET CF, .NET

Posted: 4 Mar 2008
Updated: 5 Mar 2008
Views: 4,577
Bookmarked: 12 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
6 votes for this Article.
Popularity: 2.58 Rating: 3.32 out of 5
0 votes, 0.0%
1
0 votes, 0.0%
2
4 votes, 66.7%
3
2 votes, 33.3%
4
0 votes, 0.0%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Introduction

About 3 months ago, I was asked to work out a program running on Pocket PC with .Net Compact FrameWork. It is a program drawing rooms and calculating the geometrical parameters and exporting them to XML file. The program itself , should be able to save the rooms to files and load from them.

Compact FrameWork 2.0 doesn't provide Binary Serialization. And XML Serialization is just too simple to handle what I need: I have to deal with a complex topology of object model. Room A may be associated to Room B, and Room B to Room C, Room C to Room A, it makes a circle finally, just like this:

DrawTools2005Xmlable

So, I need a way to serialize such an object model to XML. Fortunately, I had worked out something in my spare time. I call it "xmlable", just like "Serializable" in Binary Serialization.

Using the code

I will introduce Alex Fr's DrawTools to show you how this has been done.

First, include IXmlabe.cs and Xmlable.cs to your project.

Derive the classes you want to serialize from interface IXmlable, and declare an attribute Xmlable for it, and implement 2 methods of IXmlable: FromXml and ToXml

using Xmlable;
using System.Xml;

namespace DrawTools
{
    [Xmlable("DrawObject", IsUnique = false)] 
    abstract class DrawObject : IXmlable
    {
        public DrawObject(){/*...*/} // Xmlable need a constructor without parameter.

        public virtual void FromXml(XmlElement xmlEle, IXmlContext cnt)
        {
            //base.FromXml(xmlEle,cnt); //the derived classes should call parent class's FromXml
            color = Color.Black;
            try { color = Color.FromArgb(Int32.Parse(xmlEle.GetAttribute("color"))); }
            catch (Exception) { }
            penWidth = 1;
            try { penWidth = Int32.Parse(xmlEle.GetAttribute("penWidth")); }
            catch (Exception) { }
            name = xmlEle.GetAttribute("name");

            XmlElement assoEle = xmlEle["associate"];
            if(null != assoEle)
            {
                objAsso = cnt.FromXml(assoEle.FirstChild as XmlElement) as DrawObject;
            }
        }
        public virtual void ToXml(XmlElement xmlEle, IXmlContext cnt)
        {
            //base.ToXml(xmlEle,cnt); //the derived classes should call parent class's ToXml
            XmlToolkit.SetAttribute(xmlEle, "color", color.ToArgb().ToString());
            XmlToolkit.SetAttribute(xmlEle, "penWidth", penWidth.ToString());
            XmlToolkit.SetAttribute(xmlEle, "name", name);
            XmlElement assoEle = cnt.Document.CreateElement("associate");
            XmlElement objEle = cnt.ToXml(objAsso);
            if (null != objEle)
                assoEle.AppendChild(objEle);
            xmlEle.AppendChild(assoEle);
        } 
} 

[Xmlable("TagName", IsUnique = true)]
public class ClassA

means that "TagName" will be the tag name of the XML nodes of the ClassA, and IsUnique = true means whatever amount of references of a same object of type ClassA is serialized into a XML file, when the file is loaded, there would not be a lot of references refer to a lot of different objects.

In order to make DrawTools "Xmlable", the five classes : DrawObject, DrawLine, DrawPolygon, DrawRectangle, DrawEllipse and GraphicsList was modified.

GraphicsList is the container who contains DrawObject, its implement of IXmlable is like:

public virtual void FromXml(XmlElement xmlEle, IXmlContext cnt)
{
    graphicsList.Clear();
    foreach (XmlElement objEle in xmlEle)
    {
        DrawObject obj = cnt.FromXml(objEle) as DrawObject;
        System.Diagnostics.Debug.Assert(null != obj);
        if (null != obj)
        {
            graphicsList.Add(obj);
        }
    }
}

public virtual void ToXml(XmlElement xmlEle, IXmlContext cnt)
{
    foreach (DrawObject obj in graphicsList)
    {
        XmlElement objEle = cnt.ToXml(obj);
        if (null != objEle)
            xmlEle.AppendChild(objEle);
    }
}   

To save the document of DrawTools, just add some code in MainForm, like this:

Save

private void saveAsXMLToolStripMenuItem_Click(object sender, EventArgs e)
{
    if (dlgSave.ShowDialog() != DialogResult.OK)
        return ;

    XmlDocument doc = new XmlDocument();
    IXmlFormatter formatter = FepXmlableFactory.CreateXmlFormatter();
    IXmlContext cnt = FepXmlableFactory.CreateXmlContext(formatter, doc);

    XmlElement ele = cnt.ToXml(this.drawArea.GraphicsList);
    doc.AppendChild(ele);

    XmlDeclaration xmldecl;
    xmldecl = doc.CreateXmlDeclaration("1.0", null, null);
    doc.InsertBefore(xmldecl, doc.DocumentElement);

    doc.Save(dlgSave.FileName);
}

Load

private void loadFromXMLToolStripMenuItem_Click(object sender, EventArgs e)
{
    if (dlgOpen.ShowDialog() != DialogResult.OK)
        return;

    XmlDocument doc = new XmlDocument();
    doc.Load(dlgOpen.FileName);

    IXmlFormatter formatter = FepXmlableFactory.CreateXmlFormatter();
    IXmlContext cnt = FepXmlableFactory.CreateXmlContext(formatter, doc);

    GraphicsList graphList = cnt.FromXml(doc.DocumentElement) as GraphicsList;
    if(null == graphList)
        throw new System.IO.IOException(dlgOpen.FileName + " is not a valid file.");
    this.drawArea.GraphicsList = graphList;

    this.drawArea.Invalidate();
}

Hope this will help...

If you are confused by what i have written above. Just download the project, run it, draw something, right click on them, set their properties and make them associate to each other. Go to menu "File->Save As XML","File->Load From XML", and open the saved file with text editors to have a look.

I haven't done much test after I add Xmlable to DrawTools. Let's just focus on how objects be serialized to XML.

License

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

About the Author

brent.wjh


Live in Amoy China.
Occupation: Software Developer (Senior)
Company: YinhooTech
Location: China China

Other popular C# articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
  (Refresh) 
Subject  Author Date 
-- There are no messages in this forum --

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 5 Mar 2008
Editor:
Copyright 2008 by brent.wjh
Everything else Copyright © CodeProject, 1999-2008
Web07 | Advertise on the Code Project