英文:
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:
<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>
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("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
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文件(?) 一个基本的反序列化方法可以包括以下内容
模型:
<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
这将导致无序的列表,正如您所指出的那样
您可以对模型进行修改,以使用相同的类将所有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
使用相同的反序列化代码,现在您会得到这个有序的数组
英文:
You are using a hybrid method to deserialize, plus you are using a txt file(?) A basic deserialization method could involve the following
Model:
<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
Deserialization code:
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
This results in the out-of-order lists, as you noted
You can make modifications to the model to use the same class to deserialize all the type
nodes into the same array
<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
using the same deserialization code, and you now get this array, in order
答案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:
-
I renamed your classes and properties to follow MSFT's recommended naming conventions for Visual Basic, and applied XML serializer attributes to specify the names used in the XML file.
-
For similar questions in C# see https://stackoverflow.com/q/48096673/3744182 and https://stackoverflow.com/q/37307203/3744182.
Demo fiddle here.
英文:
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 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:
-
I renamed your classes and properties to follow MSFT's recommended naming conventions for Visual Basic, and applied XML serializer attributes to specify the names used in the XML file.
-
For similar questions in C# see https://stackoverflow.com/q/48096673/3744182 and https://stackoverflow.com/q/37307203/3744182.
Demo fiddle here.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论