从 XML 读取数据的顺序

Order of data read from XML

提问人:jpi76 提问时间:6/19/2023 最后编辑:djvjpi76 更新时间:6/20/2023 访问量:44

问:

我必须从 XML 文件中读取数据,顺序很重要

我有以下(简化的)XML数据需要阅读:

<xmltest>
    <type1>
        <tekst>ABC</tekst>
    </type1>
    <type2>
        <tekst>DEF</tekst>
    </type2>
    <type1>
        <tekst>GHI</tekst>
    </type1>
    <type2>
        <tekst>JKL</tekst>
    </type2>
    <type3>
        <tekst>MNO</tekst>
    </type3>
</xmltest>

创建了以下类:

public class xmltest
    public property type1 as list(of type1)
    public property type2 as list(of type2)
    public property type3 as list(of type3)
end class

public class type1
    public property tekst as string
end class

public class type2
    public property tekst as string
end class

public class type3
    public property tekst as string
end class

我使用以下代码来读取 XML:

Public Sub Indlaes
    Dim reader As New System.Xml.XmlTextReader("filename.txt")
    Dim subreader As System.Xml.XmlReader
    Dim xmlSer As System.Xml.Serialization.XmlSerializer
    Dim result = New cmltest
   
    Do While (reader.Read())
        Select Case reader.NodeType
            Case System.Xml.XmlNodeType.Element
                subreader = reader.ReadSubtree()
                xmlSer = New System.Xml.Serialization.XmlSerializer(result.GetType)
                result = xmlSer.Deserialize(subreader)
                subreader.Close()
        End Select
    Loop
    reader.Close()
End Sub

在上面的示例中,我最终在 xmltest 中得到了 3 个列表,但无法重新创建我正在考虑使用字典的顺序
,该字典在 3 个列表/字典中使用了 ID,但是我如何设置该 ID?或者有没有其他解决方案?
我真的很想继续使用 Deserialize 函数,因为它也用于其余的 xml 数据

vb.net xml 反序列化

评论

0赞 djv 6/19/2023
是否能够通过添加属性来更改架构?
0赞 jdweng 6/19/2023
你希望看到什么结果?
0赞 djv 6/19/2023
我知道你的XML是简化的,但是如果有意义的话,你可以用同一个类反序列化所有子节点
0赞 jpi76 6/20/2023
我无法控制 XML 架构

答:

0赞 djv 6/20/2023 #1

您正在使用混合方法进行反序列化,并且您正在使用 txt 文件(?)基本的反序列化方法可能涉及以下内容

型:

<XmlRoot>
Public Class xmltest
    <XmlElement>
    Public Property type1 As List(Of type1)
    <XmlElement>
    Public Property type2 As List(Of type2)
    <XmlElement>
    Public Property type3 As List(Of type3)
End Class
Public Class type1
    <XmlElement>
    Public Property tekst As String
End Class
Public Class type2
    <XmlElement>
    Public Property tekst As String
End Class
Public Class type3
    <XmlElement>
    Public Property tekst As String
End Class

反序列化代码:

Dim s As New XmlSerializer(GetType(xmltest))
Dim xmlTest As xmltest
Using fs As New FileStream("filename.xml", FileMode.Open)
    xmlTest = CType(s.Deserialize(fs), xmltest)
End Using

如您所指出的,这会导致列表乱序

enter image description here

您可以对模型进行修改,以使用相同的类将所有节点反序列化为同一数组type

<XmlRoot>
Public Class xmltest

    <XmlElement(ElementName:="type1", Type:=GetType(type1))>
    <XmlElement(ElementName:="type2", Type:=GetType(type1))>
    <XmlElement(ElementName:="type3", Type:=GetType(type1))>
    <XmlChoiceIdentifier("typesElementName")>
    Public Property types As type1()

    <XmlIgnore>
    Public Property typesElementName As types()

End Class

Public Class type1
    <XmlElement>
    Public Property tekst As String
End Class

<XmlType(IncludeInSchema:=False)>
Public Enum types
    type1
    type2
    type3
End Enum

使用相同的反序列化代码,您现在按顺序获得此数组

enter image description here

0赞 dbc 6/20/2023 #2

元素序列的架构看起来是每个可能的元素名称的选择元素序列。如选择元素绑定支持中所述,实现此目的的一种方法是通过多态类型列表,前提是您在编译时知道所有可能的元素名称,并将属性 <XmlElementAttribute(String, Type)>应用于每个可能类型的列表。<typeN><typeN><typeN>

以下类实现此方法:

' The root object with the polymorphic list corresponding to the possible types 
<XmlRoot("xmltest")> 
Public Class XmlTest
    <XmlElement("type1", GetType(Type1)), XmlElement("type2", GetType(Type2)), XmlElement("type3", GetType(Type3))>     
    Public Property TypeList As List(Of TypeBase) = New List(Of TypeBase) ()
End Class

' The <TypeN> polymorphic type hierarchy
Public Class TypeBase 
    <XmlElement("tekst")>
    Public Property Tekst As String
End Class

<XmlType("type1")>
Public Class Type1 
    Inherits TypeBase
End Class

<XmlType("type2")>
Public Class Type2
    Inherits TypeBase
End Class

<XmlType("type3")>
Public Class Type3 
    Inherits TypeBase
End Class

对于这些类,可以使用 XmlSerializer 自动反序列化,如下所示,而无需使用以下泛型函数手动读取 :XmlReader

Public Function DeserializeFromFile(Of T)(filename As String) As T
    Using stream = File.OpenRead(filename)
        Return DirectCast(New XmlSerializer(GetType(T)).Deserialize(stream), T)
    End Using
End Function

将所有这些放在一起,要反序列化 XML 文件,按其原始顺序遍历项目,并确定每个项目的类型,可以执行以下操作:<typeN>

Dim test = DeserializeFromFile(Of XmlTest)(filename)

For Each item in test.TypeList
    Select Case item.GetType()
        Case GetType(Type1)
            Console.WriteLine("Type is type 1, value is {0}.", item.Tekst)
        Case GetType(Type2)
            Console.WriteLine("Type is type 3, value is {0}.", item.Tekst)
        Case GetType(Type3)
            Console.WriteLine("Type is type 3, value is {0}.", item.Tekst)
        Case Else
            Throw New Exception(String.Format("Unknown type {0}", item.GetType()))
    End Select
Next

笔记:

在这里演示小提琴。