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.

UnknownNode Event

If you only need to know that the XML being deserialized contains some unexpected data, the easiest way to detect it is with the UnknownNode event. This event is raised for any attribute or element that does not match the class of the object being created. The event provides event arguments with an XmlNodeEventArgs instance. This provides the following properties:

  • NodeType. Describes the type of unexpected node that was encountered by returning a constant from the XmlNodeType enumeration. The value will be either Attribute or Element.
  • Name. This string property holds the name of the unexpected item. When the XML contains multiple namespaces, the Name property can include the namespace prefix.
  • LocalName. A string property holding the XML local name for the unexpected attribute or element. This does not include any namespace prefix.
  • Text. Holds the text from an unexpected element, if text is present.
  • NamespaceUri. This string property returns the node's XML namespace Uniform Resource Indicator (URI).
  • LineNumber. If you need to track down the position of the unexpected XML within a file, this property helps by providing the line number of the line containing the element or attribute.
  • LinePosition. This property returns the column position of the unexpected node. You can combine it with LineNumber to pinpoint the unknown data.
  • ObjectBeingDeserialized. This property holds a reference to the object that is being created by the deserialization process. In our example, this is the Car object in the "deserialized" variable.

Adding the Event

To attach to the event, modify the contents of the Main method as shown below. The second line uses the standard syntax for registering an event handler.

XmlSerializer serializer = new XmlSerializer(typeof(Car));
serializer.UnknownNode += UnknownNode;

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

For demonstration purposes we'll create an event handler that shows the name of the unexpected item along with its position in the file.

static void UnknownNode(object sender, XmlNodeEventArgs e)
{
    Console.WriteLine("Unexpected node: {0} as line {1}, column {2}",
        e.LocalName, e.LineNumber, e.LinePosition);
}

Running the program gives the following results:

Unexpected node: bodytype as line 2, column 16
Unexpected node: Options as line 7, column 3
Red Toyota GT86.

UnknownElement and UnknownAttribute Events

If you need more information about the unexpected items, and you will differentiate between unknown elements and attributes, you should use the UnknownElement and UnknownAttribute events.

The UnknownElement event is raised when an unexpected XML element is encountered. It is not triggered by attributes, When raised, the event provides an instance of the XmlElementEventArgs class to the event handler. This includes LineNumber, LinePosition and ObjectBeingDeserialized properties that behave in the same manner as for the XmlNodeEventArgs type. It adds a further property named, "Element", which holds an XmlElement object containing all of the details of the unknown element. You can use this to examine the XML in detail.

If you are using the .NET framework version 2.0 or a later release, the event arguments include another property named, "ExpectedElements". This is a string containing a delimited list of the element names that are recognised by the type of object being deserialized. For many cases you would know this but it can be useful when creating generic classes or generic methods that include deserialization.

The UnknownAttribute event is similar to UnknownElement but is raised in response to an unexpected attribute. Again, it includes the LineNumber, LinePosition and ObjectBeingDeserialized members and adds a new property, "Attr", containing an XmlAttribute object describing the attribute in question. In .NET 2.0 and higher versions, the ExpectedAttributes property lists the valid attributes for the target object.

To demonstrate the two events, modify the Main method to include only the following code.

XmlSerializer serializer = new XmlSerializer(typeof(Car));
serializer.UnknownAttribute += UnknownAttribute;
serializer.UnknownElement += UnknownElement;

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

Next, replace the UnknownNode method with the following two event handlers.

static void UnknownElement(object sender, XmlElementEventArgs e)
{
    Console.WriteLine("Unexpected element: {0} as line {1}, column {2}",
        e.Element.Name, e.LineNumber, e.LinePosition);
}

static void UnknownAttribute(object sender, XmlAttributeEventArgs e)
{
    Console.WriteLine("Unexpected attribute: {0} as line {1}, column {2}",
        e.Attr.Name, e.LineNumber, e.LinePosition);
}

You can now run the program to see the results. You should see that deserialization still works as expected and that the two new items are displayed by the event handlers.

Unexpected attribute: bodytype as line 2, column 16
Unexpected element: x:Options as line 7, column 3
Red Toyota GT86.
13 January 2013