Ugrás a tartalomhoz

.NET Programming Technologies

Gergely Kovásznai, Csaba Biró

Eszterházy Károly College

XML Serialization

XML Serialization

In this section, we would like briefly to sketch another XML technology, which is not related to LINQ, and is called XML serialization. Serializing objects is, in general, for saving objects into files, and later to load them back (deserialization).[14] XML serialization is a special kind of serialization, which saves objects in XML format. By using the built-in XML serializer in .NET, one can easily save objects (e.g., a list of students) into an XML file, and then load   them back easily.

We have seen earlier that the properties of classes (e.g. Student) can easily and directly be represented by XML elements (e.g. DateOfBirth) and XML attributes (e.g. FirstName). This kind of work can be automated as well. The XmlSerializer class in the System.Xml.Serialization namespace is able to serialize a (serializable) object into XML, by automatically inferencing the names of necessary XML elements and attributes.

For the sake of example, let us serialize the studentsWithCourses collection from the previous section! This collection was the result of a LINQ query, and is of type IEnumerable<Student>. Unfortunately, the IEnumerable interface is not serializable, as opposed to its own concrete implementations, such as List. Therefore, if we would like to serialize the results of our LINQ queries, they are worth to be converted to lists by using the ToList() conversion operator (Section Hiba! A hivatkozási forrás nem található.).

var studentsWithCourses = (from s in xStudents.Elements("student")

                        select new Student

                        {

                                FirstName = ...,

                                LastName = ...,

                                Sex = ...,

                                DateOfBirth = ...,

                                Courses = (from c1 in s.Element("courses").Elements("course")

                                                ...

                                                select new CourseForStudent

                                                {

                                                        Name = ...,

                                                        Grade = ...

                                                }).ToList()

                        }).ToList();

Note that not only the outer query is converted to a list, but also the inner one (which realizes a join)! Since now all the building blocks of our studentsWithCourses collection are serializable (simple types and DateTime are serializable by default), we can serialize the collection. For this, we need to instantiate XmlSerializer, for which we need to specify the type of the object being serialized (List<Student>). For serialization, one must specify a stream (a file stream in the current case), to which the system writes the serialization result. One can (very easily) write source code for serialization as follows:

XmlSerializer serializer = new XmlSerializer(typeof(List<Student>));

StreamWriter fileWriter = new StreamWriter("query.xml");

serializer.Serialize(fileWriter, studentsWithCourses);

fileWriter.Close();

The resulting query.xml will look as follows:

<?xml version="1.0" encoding="utf-8"?>

<ArrayOfStudent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

                                xmlns:xsd="http://www.w3.org/2001/XMLSchema">

        <Student>

                <FirstName>Rita</FirstName>

                <LastName>Poratzki</LastName>

                <Sex>female</Sex>

                <DateOfBirth>1992-07-12T00:00:00</DateOfBirth>

                <Courses>

                        <CourseForStudent>

                                <Name>Debugging</Name>

                                <Grade>4</Grade>

                        </CourseForStudent>

                        <CourseForStudent>

                                <Name>Visual Computing</Name>

                                <Grade>3</Grade>

                        </CourseForStudent>

                </Courses>

        </Student>

        ...

</ArrayOfStudent>

As can be seen, the resulting XML elements have the same names as the ones of our classes and of their properties. The value of the DateOfBirth property has a strange format; we have, unfortunately, no influence on this, since DateTime is not our own class (therefore it is serialized in a predetermined way). The following questions arise in connection with own classes. Is there any opportunity for serializing a property not as an XML element, but rather as an XML attribute? Can the name of an XML element/attribute differ from the name of the corresponding class/property? Can one rename the ArrayOfStudent element, corresponding to a List<Student> object in the example?

The answer for all the above questions is “yes”. In order to solve to first two problems, the System.Xml.Serialization namespace offers .NET attributes. (Do not get confused between .NET attributes and XML attributes!)

.NET attributes make it possible to attach metadata to types (e.g., classes), properties, and methods. Attributes (even several ones) must be written between brackets, and must be located right before the definition of the given type, property, or method. For example:

[Serializable]

public class MyClass

{

        [Obsolete]

        [Description("This is a method for ...")]

        public void MyMethod(...) { ... }

        [Category("Numeric")]

    public int MyProp { set; get; }

}

The above attributes, which exist in the .NET framework, are shown here as examples. The Serializable attribute declares a given class serializable; Obsolete marks a method obsolete; Description attaches a description to a method/property. Category makes it possible to divide the set of the properties of a class into categories; we can see them arranged in those categories in Visual Studio’s Properties Window (Section XVIII.1.4).

We have shown only a few examples for using .NET attributes; c.f. related literature.

In connection with XML serialization, the following .NET attributes are worth to mention:

  1. XmlType. To specify the major settings for serializing a class; e.g., how to name the XML element that corresponds to the class.

  2. XmlElement, XmlAttribute. To specify whether a property should be serialized as an XML element or as an XML attribute (and to specify related settings).

For instance, these attributes could be used in our Student class as follows:

    public enum Sex { female, male }

    [XmlType("StudentWithCourses")]

    public class Student

    {

        [XmlAttribute]

        public string FirstName { get; set; }

        [XmlAttribute]

        public string LastName { get; set; }

        [XmlAttribute("Gender")]

        public Sex Sex { get; set; }

        [XmlElement("BirthDate")]

        public DateTime DateOfBirth { get; set; }

        public List<CourseForStudent> Courses { set; get; }

    }

As can be seen, each Student object will be serialized as a StudentWithCourses XML element. The FirstName, LastName, and Sex properties will become XML attributes, instead of XML elements, and, furthermore, the latter one will be renamed to Gender. For the sake of example, we will serialize the DateOfBirth property as a BirthDate XML element, from now on.

If we have serialized our studentsWithCourses list by using the above settings, then we can notice that the root element is called ArrayOfStudentWithCourses. Even the name of this XML element can be customized in the instantiation of XmlSerializer, as follows:

XmlSerializer serializer = new XmlSerializer(typeof(List<Student>),

                                                                                new XmlRootAttribute("AllStudents"));

The result of serializing the list:

<AllStudents ...>

        <StudentWithCourses FirstName="Rita" LastName="Poratzki" Gender="female">

                <BirthDate>1992-07-12T00:00:00</BirthDate>

                <Courses>

                        <CourseForStudent Name="Debugging" Grade="4" />

                        <CourseForStudent Name="Visual Computing" Grade="3" />

                </Courses>

        </StudentWithCourses>

        ...

</AllStudents>

Suppose that you send the query.xml file, being generated right now, to someone, and he/she would like to open it in his/her application! One can open an XML file and perform queries on it as introduced in Sections XVI.1 and Hiba! A hivatkozási forrás nem található..

        There is another possibility called deserialization. It is about reading back the object that has been serialized, in a direct way, by using the XmlSerializer.Deserialize method. Suppose that we send the query.xml file to someone, who would like to open it in an own application, and then to access its content as a list of students (for which he/she will need our Student and CourseForStudent classes as well). All these things can be done in a few lines of code:

XmlSerializer serializer = new XmlSerializer(typeof(List<Student>),

                                                                                new XmlRootAttribute("AllStudents"));

StreamReader fileReader = new StreamReader("query.xml");

Students = serializer.Deserialize(fileReader) as List<Student>;

fileReader.Close();



[14] Precisely speaking, serialization is for mapping an object to a byte stream.