BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

XML
.NET 1.1+

XML Deserialization Events

The standard XML serializer is forgiving when deserializing XML documents with unexpected elements and attributes. Generally these additional XML nodes are ignored, though their existence can be identified with the use of deserialization events.

XML Serialization

Serializing objects to XML is a useful way to persist their public state in a standard format, be it to store the data for later use or to pass objects between services. XML serialization provides portability, allowing you to send messages to software that was not developed using the .NET framework and that need not be running under a Microsoft operating system.

The XML generated by the serialization process can easily be deserialized into new .NET framework objects. It can also be used to generate objects or data for other languages and frameworks to utilise. Finally, as XML can be human-readable, the produced information can even be opened in a text editor, such as Notepad, for manual examination.

XmlSerializer Events

When using the XmlSerializer class to reconstruct objects from XML, the process is forgiving of certain problems. If an unknown XML element or attribute is encountered during the process, it is ignored rather than throwing an exception. This means that the process can continue until completion and you will be given the new object, albeit it without the additional information.

This can be very useful. If your software has had multiple releases, and one or more of those versions added properties to the classes being serialized, you might not be able update all existing installations. If an old software version tried to read the data generated by a newer one, it would be unfortunate if an extra element caused the deserialization process to fail completely.

Of course, ignoring the additional XML information may not be ideal. In some cases you may want to throw an exception or otherwise react to the unexpected items. You might decide to store the additional information somewhere where the user can access it, display it and explain that it has been discarded, or simply tell the user that they must upgrade to the latest version to continue. You can implement any of these approaches using three events from the XmlSerializer class.

The three events are UnknownNode, UnknownElement and UnknownAttribute. We will look at their roles in the remainder of this article. We will be demonstrating the events with a console application that uses files on disk as well as XML serialization. To simplify the access to the namespaces required, ensure that you include the following using directives:

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

Creating the Sample Class

To begin we need a class that we can serialize. We'll use the following, which represents a car with properties for Make, Model and Colour. The overridden ToString method will let us know that the deserialization process works.

public class Car
{
    public string Make { get; set; }

    public string Model { get; set; }

    public string Colour { get; set; }

    public override string ToString()
    {
        return string.Format("{0} {1} {2}.", Colour, Make, Model);
    }
}

We can now create a new Car object and serialize it to a file using the code below. You might want to change the target path for the new file. If so, make sure you update it in the later examples too.

Add the code and run the program to generate the new file. The code also deserializes the XML into a new Car object and displays the result generated by the ToString method.

Car car = new Car();
car.Colour = "Red";
car.Make = "Toyota";
car.Model = "GT86";

XmlSerializer serializer = new XmlSerializer(car.GetType());
using (StreamWriter writer = new StreamWriter(@"c:\Test\car.xml"))
{
    serializer.Serialize(writer, car);
}

Car deserialized;
using (StreamReader reader = new StreamReader(@"c:\Test\car.xml"))
{
    deserialized = (Car)serializer.Deserialize(reader);
}
Console.WriteLine(deserialized);

Once executed, the generated XML will be similar to that shown below. Here I have removed the XML namespace details for clarity.

<?xml version="1.0" encoding="utf-8"?>
<Car>
  <Make>Toyota</Make>
  <Model>GT86</Model>
  <Colour>Red</Colour>
</Car>

Simulating a New Car Version

To simulate a new version of the Car class that our program has not been upgraded to use, we can modify the XML directly using Notepad or a similar text editor. Open the file and change its contents to that shown below. Here we have added a new attribute, bodytype, to the Car element. There's also a new XML element, Options, to hold details of the optional extras for the car. Neither of these new items can be stored in the current version of the Car class so will be ignored by deserialization.

<?xml version="1.0" encoding="utf-8"?>
<Car bodytype="Sports">
  <Make>Toyota</Make>
  <Model>GT86</Model>
  <Colour>Red</Colour>
  <Options>Leather Seats</Options>
</Car>

Modify the Main method to remove the serialization part, so that the file is not overwritten. The new Main method should contain only the code shown below. When you run the program you should see that the XML is still deserialized without error and the produced Car contains the correct details from the known properties. The extra attribute and element are ignored.

XmlSerializer serializer = new XmlSerializer(typeof(Car));

Car deserialized;
using (StreamReader reader = new StreamReader(@"c:\Test\car.xml"))
{
    deserialized = (Car)serializer.Deserialize(reader);
}
Console.WriteLine(deserialized);
13 January 2013