views:

243

answers:

1

I've been working with Xml Serialization/Deserialization in .net and wanted a method where the serialization/deserialization process would only be applied to certain parts of an Xml fragment. This is so I can keep certain parts of the fragment in Xml after the deserialization process.

To do this I thought it would be best to create a new class (XmlLiteral) that implemented IXmlSerializable and then wrote specific code for handling the IXmlSerializable.ReadXml and IXmlSerializable.WriteXml methods.

In my example below this works for Serializing, however during the Deserialization process it fails to run for multiple uses of my XmlLiteral class. In my example below sTest1 gets populated correctly, but sTest2 and sTest3 are empty.

I'm guessing I must be going wrong with the following lines but can't figure out why.. Any ideas at all?

    Private Sub ReadXml(ByVal reader As System.Xml.XmlReader) Implements IXmlSerializable.ReadXml
        Dim StringType As String = ""
        If reader.IsEmptyElement OrElse reader.Read() = False Then
            Exit Sub
        End If
        _src = reader.ReadOuterXml()
    End Sub

Full listing:

Imports System
Imports System.Xml.Serialization
Imports System.Xml
Imports System.IO
Imports System.Text

Public Class XmlLiteralExample
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim MyObjectInstance As New MyObject

        MyObjectInstance.aProperty = "MyValue"
        MyObjectInstance.XmlLiteral1 = New XmlLiteral("<test1>Some Value</test1>")
        MyObjectInstance.XmlLiteral2 = New XmlLiteral("<test2>Some Value</test2>")
        MyObjectInstance.XmlLiteral3 = New XmlLiteral("<test3>Some Value</test3>")

        ' quickly serialize the object to Xml
        Dim sw As New StringWriter(New StringBuilder())
        Dim s As New XmlSerializer(MyObjectInstance.[GetType]()), xmlnsEmpty As New XmlSerializerNamespaces
        xmlnsEmpty.Add("", "")
        s.Serialize(sw, MyObjectInstance, xmlnsEmpty)
        Dim XElement As XElement = XElement.Parse(sw.ToString())

        ' XElement reads as the following, so serialization works OK
        '<MyObject>
        '  <aProperty>MyValue</aProperty>
        '  <XmlLiteral1>
        '    <test1>Some Value</test1>
        '  </XmlLiteral1>
        '  <XmlLiteral2>
        '    <test2>Some Value</test2>
        '  </XmlLiteral2>
        '  <XmlLiteral3>
        '    <test3>Some Value</test3>
        '  </XmlLiteral3>
        '</MyObject>

        ' quickly deserialize the object back to an instance of MyObjectInstance2
        Dim MyObjectInstance2 As New MyObject
        Dim xmlReader As XmlReader, x As XmlSerializer
        xmlReader = XElement.CreateReader
        x = New XmlSerializer(MyObjectInstance2.GetType())
        MyObjectInstance2 = x.Deserialize(xmlReader)

        Dim sProperty As String = MyObjectInstance2.aProperty ' equal to "MyValue"
        Dim sTest1 As String = MyObjectInstance2.XmlLiteral1.Text ' contains <test1>Some Value</test1>
        Dim sTest2 As String = MyObjectInstance2.XmlLiteral2.Text ' is empty
        Dim sTest3 As String = MyObjectInstance2.XmlLiteral3.Text ' is empty

        ' sTest3 and sTest3 should be populated but are not?

        xmlReader = Nothing

    End Sub

    Public Class MyObject
        Private _aProperty As String
        Private _XmlLiteral1 As XmlLiteral
        Private _XmlLiteral2 As XmlLiteral
        Private _XmlLiteral3 As XmlLiteral

        Public Property aProperty As String
            Get
                Return _aProperty
            End Get
            Set(ByVal value As String)
                _aProperty = value
            End Set
        End Property

        Public Property XmlLiteral1 As XmlLiteral
            Get
                Return _XmlLiteral1
            End Get
            Set(ByVal value As XmlLiteral)
                _XmlLiteral1 = value
            End Set
        End Property

        Public Property XmlLiteral2 As XmlLiteral
            Get
                Return _XmlLiteral2
            End Get
            Set(ByVal value As XmlLiteral)
                _XmlLiteral2 = value
            End Set
        End Property

        Public Property XmlLiteral3 As XmlLiteral
            Get
                Return _XmlLiteral3
            End Get
            Set(ByVal value As XmlLiteral)
                _XmlLiteral3 = value
            End Set
        End Property

        Public Sub New()
            _XmlLiteral1 = New XmlLiteral
            _XmlLiteral2 = New XmlLiteral
            _XmlLiteral3 = New XmlLiteral
        End Sub

    End Class

    <System.Xml.Serialization.XmlRootAttribute(Namespace:="", IsNullable:=False)> _
    Public Class XmlLiteral
        Implements IXmlSerializable
        Private _src As String

        Public Property Text() As String
            Get
                Return _src
            End Get
            Set(ByVal value As String)
                _src = value
            End Set
        End Property

        Public Sub New()
            _src = ""
        End Sub

        Public Sub New(ByVal Text As String)
            _src = Text
        End Sub

#Region "IXmlSerializable Members"

        Private Function GetSchema() As System.Xml.Schema.XmlSchema Implements IXmlSerializable.GetSchema
            Return Nothing
        End Function

        Private Sub ReadXml(ByVal reader As System.Xml.XmlReader) Implements IXmlSerializable.ReadXml
            Dim StringType As String = ""
            If reader.IsEmptyElement OrElse reader.Read() = False Then
                Exit Sub
            End If
            _src = reader.ReadOuterXml()
        End Sub

        Private Sub WriteXml(ByVal writer As System.Xml.XmlWriter) Implements IXmlSerializable.WriteXml
            writer.WriteRaw(_src)
        End Sub

#End Region

    End Class

End Class
A: 

Managed to fix this by working some more on the ReadXml method. After more research I found out that it is very important to end the ReadXml method with reader.ReadEndElement() so that the next reader works correctly. Hope this solutions helps somebody out!

    Private Sub ReadXml(ByVal reader As System.Xml.XmlReader) Implements IXmlSerializable.ReadXml
        If reader.IsEmptyElement OrElse reader.Read() = False Then
            Exit Sub
        End If
        While reader.NodeType <> System.Xml.XmlNodeType.EndElement
            _src = reader.ReadOuterXml
        End While
        reader.ReadEndElement()
    End Sub
sw1sh