使用XmlReader和忽略节点顺序

时间:2014-02-11 16:07:25

标签: vb.net serialization xml-serialization xmlreader backwards-compatibility

我正在尝试实现'IXmlSerializable'接口并努力实现'ReadXml'。这是我的序列化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>

有一个“小”特殊要求,反序列化必须向后兼容到可能具有不同元素顺序的旧序列化版本,缺少元素或者有其他(现在未使用过的)元素。我怎么能这样做?

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

2 个答案:

答案 0 :(得分:2)

这对我有用。它在节点顺序方面完全灵活。

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

答案 1 :(得分:0)

以下是一些用于解析地理编码数据的代码,这些代码可以帮助您完成大部分工作。

在你的Case'ArrayProperty'中你需要使用Reader.Read来嵌套元素。

   URL = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.placefinder%20where%20text%3D%22{0}%22&diagnostics=true"
    URL = String.Format(URL, sLocation)
     Try
        reader = New XmlTextReader(URL)
        'reader.WhitespaceHandling = WhitespaceHandling.None 'Disable whitespace so that you don't have to read over whitespaces
        With Address
            While (reader.Read())
                Debug.Print(reader.Name.ToString())
                Select Case reader.Name.ToString()
                    Case "Result"
                        If reader.HasAttributes Then
                            For i = 0 To CShort(reader.AttributeCount - 1)
                                reader.MoveToAttribute(i)
                                Select Case reader.Name.ToString
                                    Case "precision"
                                        .precision = reader.GetAttribute(reader.Name.ToString)
                                    Case "warning"
                                        .warning = reader.GetAttribute(reader.Name.ToString)
                                        bOK = False
                                End Select
                                reader.MoveToElement() ' Move the reader back to the element node.
                            Next
                        End If
                    Case "ErrorMessage"
                        .warning = reader.ReadString().ToString()
                    Case "quality"
                        .precision = reader.ReadString().ToString()
                    Case "line1"
                        .Street = reader.ReadString().ToString()
                    Case "city"
                        .City = reader.ReadString().ToString()
                    Case "statecode"
                        .State = reader.ReadString().ToString()
                    Case "postal"
                        .Zip = reader.ReadString().ToString()
                    Case "country"
                        .Country = reader.ReadString().ToString()
                    Case "offsetlat"
                        .Latitude = reader.ReadString().ToString()
                    Case "offsetlon"
                        .Longitude = reader.ReadString().ToString()
                End Select
            End While
        End With
    Catch ex As Exception
        bOK = False
        Address.warning = ex.Message
    End Try

对于上面的代码,我只使用下面的代码作为“地址”类:

Private Structure Address_struct
    Public Street As String
    Public City As String
    Public State As String
    Public Zip As String
    Public Country As String
    Public Latitude As String
    Public Longitude As String
    Public precision As String
    Public warning As String
End Structure
Dim Address As Address_struct