You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XML数据读取时如何保留节点顺序?(基于XmlSerializer)

保留XML节点顺序的XmlSerializer读取方案

问题背景

需要读取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

当前使用的读取代码:

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 xmltest
   
    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对象的三个List能正确收集对应类型的节点,但无法还原原始XML中的节点顺序。考虑过用带跨列表ID的字典,但不知道如何设置ID;希望继续使用XmlSerializer,因为其余XML数据依赖该工具。


解决方案:用统一有序集合保留节点顺序

核心思路是让XmlSerializer把不同类型的节点反序列化到一个单一有序集合中,同时识别每个节点的类型。以下是两种可行实现方式:

方式1:基类+XmlInclude+List(Of 基类)

  1. 定义基类,让所有节点类型继承它:
Public Class BaseType
    ' 仅作为父类型标识,无需额外属性
End Class

Public Class type1
    Inherits BaseType
    Public Property tekst As String
End Class

Public Class type2
    Inherits BaseType
    Public Property tekst As String
End Class

Public Class type3
    Inherits BaseType
    Public Property tekst As String
End Class
  1. 修改xmltest类,替换原有三个List为统一的有序集合,并添加序列化特性指定节点映射:
<XmlSerializer.XmlInclude(GetType(type1))>
<XmlSerializer.XmlInclude(GetType(type2))>
<XmlSerializer.XmlInclude(GetType(type3))>
Public Class xmltest
    <XmlSerializer.XmlElement("type1", GetType(type1))>
    <XmlSerializer.XmlElement("type2", GetType(type2))>
    <XmlSerializer.XmlElement("type3", GetType(type3))>
    Public Property Items As List(Of BaseType)
End Class
  1. 简化读取代码,直接反序列化整个对象:
Public Sub Indlaes()
    Dim xmlSer As New System.Xml.Serialization.XmlSerializer(GetType(xmltest))
    Using reader As New System.Xml.XmlTextReader("filename.txt")
        Dim result = DirectCast(xmlSer.Deserialize(reader), xmltest)
        ' result.Items的顺序完全匹配XML节点顺序
        ' 遍历处理时通过GetType()判断节点类型
        For Each item In result.Items
            Select Case item.GetType()
                Case GetType(type1)
                    Dim t1 = DirectCast(item, type1)
                    ' 处理type1节点逻辑
                Case GetType(type2)
                    Dim t2 = DirectCast(item, type2)
                    ' 处理type2节点逻辑
                Case GetType(type3)
                    Dim t3 = DirectCast(item, type3)
                    ' 处理type3节点逻辑
            End Select
        Next
    End Using
End Sub

方式2:直接用List(Of Object)+XmlElement属性(无需基类)

如果不想定义基类,可直接用List(Of Object)实现相同效果:

<XmlSerializer.XmlInclude(GetType(type1))>
<XmlSerializer.XmlInclude(GetType(type2))>
<XmlSerializer.XmlInclude(GetType(type3))>
Public Class xmltest
    <XmlSerializer.XmlElement("type1", GetType(type1))>
    <XmlSerializer.XmlElement("type2", GetType(type2))>
    <XmlSerializer.XmlElement("type3", GetType(type3))>
    Public Property Items As List(Of Object)
End Class

读取和处理代码与方式1一致,仅在类型转换时将BaseType替换为Object即可。


原代码失效原因

原代码循环读取每个元素并重复反序列化到xmltest对象,每次反序列化会覆盖之前的List内容;且XmlSerializer默认将同类型节点收集到独立List中,三个List无法体现节点交叉出现的顺序关系。

内容的提问来源于stack exchange,提问作者jpi76

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:35:27