Search code examples
vb.netserializationxml-serializationxmlreaderbackwards-compatibility

Use XmlReader and Ignore Order of Nodes


I'm trying to implement the 'IXmlSerializable' interface and struggle with the 'ReadXml' implementation. Here is my serialized xml:

<?xml version="1.0" encoding="utf-16"?>
<MyClass>
  <IntProperty>100</IntProperty>
  <BoolProperty>True</BoolProperty>
  <ArrayProperty>
    <ArrayEntry MyAttr="Bob" />
    <ArrayEntry MyAttr="Alice" />
  </ArrayProperty>
  <StringProperty>Hello World!</StringProperty>
</MyClass>

There is this "little" special requirement that the deserialization must be backwards-compatible to older serialized versions which have might have a different order of elements, are missing elements or have additional (now unused) elements. How can I do this?

Public Class MyClass
  Implements IXmlSerializable

    Public Property IntProperty As Integer
    Public Property BoolProperty As Boolean
    Public Property ArrayProperty As ArrayEntry()
    Public Property StringProperty As String

    Public Sub ReadXml(reader As System.Xml.XmlReader) Implements IXmlSerializable.ReadXml
        ' to be done ...
    End Sub

    ' ...

End Class

Public Class ArrayEntry
    Public Property MyAttr As String
End Class

Solution

  • Here is what works for me. It's fully flexible in regard to the order of the nodes.

    Public Sub ReadXml(reader As System.Xml.XmlReader) Implements IXmlSerializable.ReadXml
    
        reader.MoveToContent()
    
        While True
            Select Case reader.Name
                Case "IntProperty"
                    IntProperty = CInt(reader.ReadString())
                Case "BoolProperty"
                    BoolProperty = CBool(reader.ReadString())
                Case "StringProperty"
                    StringProperty = reader.ReadString()
                Case "ArrayProperty"
                    Dim arrayEntries As New List(Of ArrayEntry)
                    If Not reader.IsEmptyElement Then
                        While reader.Read()
                            If reader.Name <> "ArrayEntry" Then Exit While
                            Dim ar As New ArrayEntry
                            ar.MyAttr = reader.GetAttribute("MyAttr")
                            arrayEntries.Add(ar)
                        End While
                    End If
                    ArrayProperty = arrayEntries.ToArray()
            End Select
            If Not reader.Read() Then Exit While
        End While
    
    End Sub