Sunday, July 31, 2005

XML Serialization of a record list

XML Serialization only serializes public data, so I wrote a small contact book application that demonstrates serializing collections by creating a couple of records consisting of name and phone number objects and serializing them.
I wouldnt want to define my variables as public, so I defined them as private, but exposed them through public properties, in which we could implement value checks etc. I annotated those properties with the [XmlElement] attribute so that each of those properties when serialized would become an XML Element as you would see shortly. I did similar with the name class. Note that you need to define default constructors.

public class PhoneNumber
{
int _countryCode;
int _cityCode;
int _number;

[XmlElement("CountryCode")]
public int CountryCode
{
set { _countryCode = value; }
get { return _countryCode; }
}

[XmlElement("CityCode")]
public int CityCode
{
set { _cityCode = value; }
get { return _cityCode; }
}

[XmlElement("Number")]
public int Number
{
set { _number = value; }
get { return _number; }
}

public PhoneNumber(int countryCode, int cityCode, int number)
{
_countryCode = countryCode;
_cityCode = cityCode;
_number = number;
}
public PhoneNumber()
{
}
}

public class Name
{
string _firstName;
string _middleName;
string _lastName;

public Name(string firstName, string middleName, string lastName)
{
_firstName = firstName;
_middleName = middleName;
_lastName = lastName;
}
public Name()
{
}

[XmlElement("firstname")]
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}

[XmlElement("middlename")]
public string MiddleName
{
get { return _middleName; }
set { _middleName = value; }
}

[XmlElement("lastname")]
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
}


Then, I defined the Record class that aggregates Name and PhoneNumber. I defined private members for name and phone number and exposed them through public properties, annotated with [XmlElement] attributes.

public class Record
{
Name _name;
PhoneNumber _phoneNumber;

[XmlElement("Name")]
public Name name
{
set { _name = value; }
get { return _name; }
}

[XmlElement("PhoneNumber")]
public PhoneNumber phoneNumber
{
set { _phoneNumber = value; }
get { return _phoneNumber; }
}
public Record()
{
}
}


Then, our top level class, which I was too lazy to rename from the VS .NET name Class1, I annotated it with the [XmlRoot] attribute to provide a name for the XML root element. Then, in the accessors for the records, I annotated it with the [XmlElement] attribute so that the name and phone number elements would be nested inside a Record element and Record elements would be inside the root element. Of course, there can only be one XML root element for a document. I also implemented a get accessor indexer so that you could access collection elements through array-like syntax. The rest of the code isnt too difficult to follow.

[XmlRoot("NameList")]
public class Class1
{
ArrayList _nameList;

public Class1()
{
_nameList = new ArrayList();
}

[XmlElement("Record")]
public Record[] Records
{
get
{
Record[] names = new Record[_nameList.Count];
_nameList.CopyTo(names);
return names;
}
set
{
if ( value == null )
return;
Record[] names = (Record[]) value;
_nameList.Clear();
foreach (Record name in value)
_nameList.Add(name);
}
}

public Record this [int index]
{
get
{
return (index < _nameList.Count) ? (Record) _nameList[index] : (Record) null;
}
}

public void Add(Record rec)
{
if (rec != null)
_nameList.Add(rec);
}
///
/// The main entry point for the application.
///

[STAThread]
static void Main(string[] args)
{
Class1 oMain = new Class1();
Name hisName = new Name("Adnan", "Farooq", "Hashmi");
Name anotherName = new Name("Hammad", "", "Rajjoub");
PhoneNumber ph1 = new PhoneNumber(92, 21, 888222);
PhoneNumber ph2 = new PhoneNumber(92, 21, 777333);
Record rec1 = new Record();
rec1.name = hisName;
rec1.phoneNumber = ph1;
Record rec2 = new Record();
rec2.name = anotherName;
rec2.phoneNumber = ph2;
oMain.Add(rec1);
oMain.Add(rec2);
XmlSerializer ser = new XmlSerializer(typeof(Class1));
StreamWriter sw = new StreamWriter("data.xml");
ser.Serialize(sw,oMain);
sw.Close();
}
}


I was a bit miserly with comments on this, which is rare. The reason is that I had a couple of other programs to do today, and I also had to do extra time on campus this morning to finish off some unfinished business.
If you're as lazy as I am, or even beat me, which is difficult, because lazy people are too lazy to beat others, just download the source code. I am including the XML file for good measure. Dont blame me for the stupid application, I am a lousy developer.

3 comments:

M Shoaib Sheikh said...

sir i wonna ask u one thing that y u have become so much object-oriented abt ur 2 Mvp friends.....:)encapsulating mvps in objects .......

Muhammad Saqib Ilyas said...

lol. Yeah, that's true. Whoever brings any code to test, I enter these guys into the program. They're my guinea pigs, or test cases or whatever you want to call it. I guess it's just that their names come first to my mind. They're great friends.

Sarfaraz Ahmed Soomro said...

even though i didn't annotated the fields as XMLElement or XMLRoot, but still it worked fine, the top most object on the aggregation hierarchy stood as the root element. Not able to serialize the pvt fields forced me to even expose fields like id and pw :(.