XML中数据读取的顺序

huangapple go评论56阅读模式
英文:

Order of data read from XML

问题

我必须从一个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 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内的3个列表,但无法重建顺序。
我考虑使用一个带有在3个列表/字典之间使用的ID的字典,但如何设置ID呢?或者还有其他解决方案吗?
我真的想继续使用Deserialize函数,因为它也用于其他XML数据。

英文:

I have to read data from an XML file and the order is important

I have the following (simplified) XML data which I need to read:

&lt;xmltest&gt;
    &lt;type1&gt;
        &lt;tekst&gt;ABC&lt;/tekst&gt;
    &lt;/type1&gt;
    &lt;type2&gt;
        &lt;tekst&gt;DEF&lt;/tekst&gt;
    &lt;/type2&gt;
    &lt;type1&gt;
        &lt;tekst&gt;GHI&lt;/tekst&gt;
    &lt;/type1&gt;
    &lt;type2&gt;
        &lt;tekst&gt;JKL&lt;/tekst&gt;
    &lt;/type2&gt;
    &lt;type3&gt;
        &lt;tekst&gt;MNO&lt;/tekst&gt;
    &lt;/type3&gt;
&lt;/xmltest&gt;

The following classes are made:

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

I use the following code to read the XML:

Public Sub Indlaes
    Dim reader As New System.Xml.XmlTextReader(&quot;filename.txt&quot;)
    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

In the above example I end up with 3 lists inside the xmltest but can't recreate the order
<br>I'm thinking about using a dictionary with an ID used across the 3 lists/dictionaries, but how do I get the ID's set? Or is there any other solution?
<br>I would really want to keep using the Deserialize function as it is used for the rest of the xml data also

答案1

得分: 0

你正在使用混合方法进行反序列化,另外你还在使用一个txt文件(?) 一个基本的反序列化方法可以包括以下内容

模型:

&lt;XmlRoot&gt;
Public Class xmltest
    &lt;XmlElement&gt;
    Public Property type1 As List(Of type1)
    &lt;XmlElement&gt;
    Public Property type2 As List(Of type2)
    &lt;XmlElement&gt;
    Public Property type3 As List(Of type3)
End Class
Public Class type1
    &lt;XmlElement&gt;
    Public Property tekst As String
End Class
Public Class type2
    &lt;XmlElement&gt;
    Public Property tekst As String
End Class
Public Class type3
    &lt;XmlElement&gt;
    Public Property tekst As String
End Class

反序列化代码:

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

这将导致无序的列表,正如您所指出的那样

XML中数据读取的顺序

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

&lt;XmlRoot&gt;
Public Class xmltest

    &lt;XmlElement(ElementName:=&quot;type1&quot;, Type:=GetType(type1))&gt;
    &lt;XmlElement(ElementName:=&quot;type2&quot;, Type:=GetType(type1))&gt;
    &lt;XmlElement(ElementName:=&quot;type3&quot;, Type:=GetType(type1))&gt;
    &lt;XmlChoiceIdentifier(&quot;typesElementName&quot;)&gt;
    Public Property types As type1()

    &lt;XmlIgnore&gt;
    Public Property typesElementName As types()

End Class

Public Class type1
    &lt;XmlElement&gt;
    Public Property tekst As String
End Class

&lt;XmlType(IncludeInSchema:=False)&gt;
Public Enum types
    type1
    type2
    type3
End Enum

使用相同的反序列化代码,现在您会得到这个有序的数组

XML中数据读取的顺序

英文:

You are using a hybrid method to deserialize, plus you are using a txt file(?) A basic deserialization method could involve the following

Model:

&lt;XmlRoot&gt;
Public Class xmltest
    &lt;XmlElement&gt;
    Public Property type1 As List(Of type1)
    &lt;XmlElement&gt;
    Public Property type2 As List(Of type2)
    &lt;XmlElement&gt;
    Public Property type3 As List(Of type3)
End Class
Public Class type1
    &lt;XmlElement&gt;
    Public Property tekst As String
End Class
Public Class type2
    &lt;XmlElement&gt;
    Public Property tekst As String
End Class
Public Class type3
    &lt;XmlElement&gt;
    Public Property tekst As String
End Class

Deserialization code:

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

This results in the out-of-order lists, as you noted

XML中数据读取的顺序

You can make modifications to the model to use the same class to deserialize all the type nodes into the same array

&lt;XmlRoot&gt;
Public Class xmltest

    &lt;XmlElement(ElementName:=&quot;type1&quot;, Type:=GetType(type1))&gt;
    &lt;XmlElement(ElementName:=&quot;type2&quot;, Type:=GetType(type1))&gt;
    &lt;XmlElement(ElementName:=&quot;type3&quot;, Type:=GetType(type1))&gt;
    &lt;XmlChoiceIdentifier(&quot;typesElementName&quot;)&gt;
    Public Property types As type1()

    &lt;XmlIgnore&gt;
    Public Property typesElementName As types()

End Class

Public Class type1
    &lt;XmlElement&gt;
    Public Property tekst As String
End Class

&lt;XmlType(IncludeInSchema:=False)&gt;
Public Enum types
    type1
    type2
    type3
End Enum

using the same deserialization code, and you now get this array, in order

XML中数据读取的顺序

答案2

得分: 0

以下是翻译好的部分:

The schema for your sequence of <typeN> elements looks to be a sequence of choice elements for each of possible <typeN> element name. As explained in Choice Element Binding Support, one way to implement this is via a list of polymorphic types, provided you know all possible <typeN> element names at compile time, and apply the attributes <XmlElementAttribute(String, Type)> to the list for each possible type.

The following classes implement this approach:

' 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

With these classes, you can deserialize automatically using XmlSerializer as follows, without any need for manual reading with XmlReader, using the following generic function:

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

Putting it all together, to deserialize your XML file, loop through the <typeN> items in their original order, and determine the type of each, you could do the following:

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

Notes:

Demo fiddle here.

英文:

The schema for your sequence of &lt;typeN&gt; elements looks to be a sequence of choice elements for each of possible &lt;typeN&gt; element name. As explained in Choice Element Binding Support, one way to implement this is via a list of polymorphic types, provided you know all all possible &lt;typeN&gt; element names at compile time, and apply the attributes &lt;XmlElementAttribute(String, Type)&gt; to the list for each possible type.

The following classes implement this approach:

&#39; The root object with the polymorphic list corresponding to the possible types	
&lt;XmlRoot(&quot;xmltest&quot;)&gt; 
Public Class XmlTest
	&lt;XmlElement(&quot;type1&quot;, GetType(Type1)), XmlElement(&quot;type2&quot;, GetType(Type2)), XmlElement(&quot;type3&quot;, GetType(Type3))&gt; 	
	Public Property TypeList As List(Of TypeBase) = New List(Of TypeBase) ()
End Class

&#39; The &lt;TypeN&gt; polymorphic type hierarchy
Public Class TypeBase 
    &lt;XmlElement(&quot;tekst&quot;)&gt;
	Public Property Tekst As String
End Class

&lt;XmlType(&quot;type1&quot;)&gt;
Public Class Type1 
	Inherits TypeBase
End Class

&lt;XmlType(&quot;type2&quot;)&gt;
Public Class Type2
	Inherits TypeBase
End Class

&lt;XmlType(&quot;type3&quot;)&gt;
Public Class Type3 
	Inherits TypeBase
End Class

With these classes, you can deserialize automatically using XmlSerializer as follows, without any need for manual reading with XmlReader, using the following generic function:

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

Putting it all together, to deserialize your XML file, loop through the &lt;typeN&gt; items in their original order, and determine the type of each, you could do the following:

Dim test = DeserializeFromFile(Of XmlTest)(filename)

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

Notes:

Demo fiddle here.

huangapple
  • 本文由 发表于 2023年6月19日 20:40:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76506717.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定