如何同时检索子节点和父节点XML节点的值?
<Drawer_System_1>
<DrawerSystemID>1</DrawerSystemID>
<DrawerSysName>Drawer_System_1</DrawerSysName>
<DrawerSysLocation>North Wall (2nd from left)</DrawerSysLocation>
<Drawers>
<DrawerID>1-01</DrawerID>`enter code here`
<Contents>Contents of Drawer 1-01</Contents>
</Drawers>
<Drawers>
<DrawerID>1-02</DrawerID>
<Contents>Contents of Drawer 1-02</Contents>
</Drawers>
</Drawer_System_1>
我的问题
如何取回孩子的同时值和父XML节点?
我已经用我的XML文件填充了一个TreeView控件,并且我想在节点和子节点之间检索某些值(如字符串),因为我在控件中选择它们。
我的预期结果
如果我选择Drawer_System_1节点或任何子节点,我想要检索DrawerSysLocation节点DrawerSystemID,DrawerSysName之间的值,和。
如果我选择一个抽屉节点或任何子节点,我想保留前面提到的值,并检索DrawerID和内容节点的值。
每个节点的值应显示在单独的标签中,但如果它更容易在多行文本框(或标签)中显示我所请求的数据,那也可以。
注意
我使用VB.NET,但如果你能想到在C#中的解决方案,那也没关系 - 我应该能够使用an online converter答案转换为VB。
如果有必要,我可以重新构建我的XML文件,使我的程序更容易阅读。
编辑:这是我到目前为止的代码:
Imports System
Imports System.Xml
Imports System.Xml.Serialization
Imports System.IO
Public Class My_LEGO_Elements
Private Sub My_LEGO_Elements_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim serializer As New SimpleXmlSerializer()
Dim data As LEGOElementsData = serializer.DeSerialize(Of LEGOElementsData)(File.ReadAllText("C:\Users\Steven\Documents\Visual Studio 2012\Projects\My_LEGO_Elements\My_LEGO_Elements\Drawer_Systems_5.xml"))
ListBox1.Items.AddRange(data.DrawerSystems.ToArray())
End Sub
Private Sub ListBox1_SelectedValueChanged(ByVal sender As Object, ByVal e As EventArgs) Handles ListBox1.SelectedValueChanged
Dim drawerSystem As DrawerSystem = CType(ListBox1.SelectedItem, DrawerSystem)
DrawerSysIDLabel.Text = drawerSystem.Id
DrawerSysNameLabel.Text = drawerSystem.Name
DrawerSysLocLabel.Text = drawerSystem.Location
'retrieve specific drawer system image from resources
Dim pictureResource = My.Resources.ResourceManager.GetObject(String.Format("{0}", drawerSystem.Id))
'convert pictureResource to type Image and display in DrawerSysPictureBox
DrawerSysPictureBox.Image = CType(pictureResource, Image)
End Sub 'My_LEGO_Elements_Load
Private Sub ListBox2_SelectedValueChanged(ByVal sender As Object, ByVal e As EventArgs) Handles ListBox2.SelectedValueChanged
Dim drawer As Drawer = CType(ListBox2.SelectedItem, Drawer)
DrawerNumberLabel.Text = drawer.Id
DrawerContentsLabel.Text = drawer.Contents
End Sub
End Class 'My_LEGO_Elements
Public Class LEGOElementsData
Public Property DrawerSystems() As List(Of DrawerSystem)
Get
Return _drawerSystems
End Get
Set(ByVal value As List(Of DrawerSystem))
_drawerSystems = value
End Set
End Property
Private _drawerSystems As List(Of DrawerSystem)
End Class
Public Class DrawerSystem
Public Property Id() As String
Get
Return _id
End Get
Set(ByVal value As String)
_id = value
End Set
End Property
Private _id As String
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Private _name As String
Public Property Location() As String
Get
Return _location
End Get
Set(ByVal value As String)
_location = value
End Set
End Property
Private _location As String
Public Property Drawers() As List(Of Drawer)
Get
Return _drawers
End Get
Set(ByVal value As List(Of Drawer))
_drawers = value
End Set
End Property
Private _drawers As List(Of Drawer)
Public Overrides Function ToString() As String
Return _name
End Function
End Class
Public Class Drawer
Public Property Id() As String
Get
Return _id
End Get
Set(ByVal value As String)
_id = value
End Set
End Property
Private _id As String
Public Property Contents() As String
Get
Return _contents
End Get
Set(ByVal value As String)
_contents = value
End Set
End Property
Private _contents As String
End Class
Public Class SimpleXmlSerializer
Public Function Serialize(ByVal objectToSerialize As Object) As String
Dim serializer As XmlSerializer = New XmlSerializer(objectToSerialize.GetType())
Using stream As MemoryStream = New MemoryStream()
Dim namespaces As XmlSerializerNamespaces = New XmlSerializerNamespaces()
namespaces.Add("", "")
serializer.Serialize(stream, objectToSerialize, namespaces)
Using reader As StreamReader = New StreamReader(stream)
stream.Position = 0
Return reader.ReadToEnd()
End Using
End Using
End Function
Public Function DeSerialize(Of T)(ByVal serializedObject As String) As T
Dim serializer As XmlSerializer = New XmlSerializer(GetType(T))
Using reader As StringReader = New StringReader(serializedObject)
Return CType(serializer.Deserialize(reader), T)
End Using
End Function
End Class
我重新构造我的XML文件的建议。我将抽屉系统信息正确显示。在选择抽屉系统后,有没有办法在第二个ListBox(或其他类型的控件)中显示关于单个抽屉的信息?另外,出于某种原因,我的图像将不会显示在PictureBox中。
听起来像一个奇怪的方式来做到这一点。我想如果你将XML加载到TreeView控件中,那么你会将所有必要的数据存储到TreeNode.Tag
属性中,或者存储在TreeView之外的内存中的某些数据结构中,这样当他们选择一个节点时,不必回到XML来获取子元素的数据。但是,如果这是你想要做什么,这里是读取数据了XML的一种方式:
Dim xmlText As String = "<Drawer_System_1>...</Drawer_System_1>..."
Dim doc As New XmlDocument()
doc.LoadXml(xmlText)
Dim parentNode As XmlNode = doc.SelectSingleNode("//Drawer_System_1")
Dim drawerSystemID As String = parentNode.SelectSingleNode("DrawerSystemID").InnerText
Dim drawerSysName As String = parentNode.SelectSingleNode("DrawerSysName").InnerText
Dim drawerSysLocation As String = parentNode.SelectSingleNode("DrawerSysLocation").InnerText
的TreeNode.Tag
属性仅仅是一个Object
属性,你可以设置为你想要的任何东西。您可以将它设置为等于一个字符串,一个列表,一个数据集,您自己的自定义对象或其他任何东西。无论对你来说什么都有道理,这就是它的目的。它允许您将有关树中每个节点的自定义数据存储在树中,以便以后可以访问它(例如选择节点时)。因此,举例来说,如果你有自己的类这样的:
Public Class DrawerSystem
Public ID As String
Public Name As String
Public Location As String
End Class
然后,当你对一个抽屉系统创建一个'树节点”,你可以设置是这样的标签:
Private Sub AddNode(drawerSystem As DrawerSystem)
Dim node As TreeNode = TreeView1.Nodes.Add(drawerSystem.Name)
node.Tag = drawerSystem
End Sub
然后在一个节点被点击或选中时的情况下,例如,你可以检索该对象是这样的:
Dim drawerSystem As DrawerSystem = CType(e.Node.Tag, DrawerSystem)
Label1.Text = drawerSystem.ID
Label2.Text = drawerSystem.Location
我不明白到底为什么你需要显示所有的XML在同一个元素教主y在TreeView中。看起来像一个简单的抽屉系统清单就足够了。然后,当列表中的某个项目被选中时,您可以在其他控件中显示该抽屉系统的所有详细信息。另外,我不建议循环访问XML,而是建议将XML反序列化为匹配的数据结构。举例来说,如果你重新格式化你这样的XML(只是为了使之更加有利于反序列化):
<LegoElementsData>
<DrawerSystems>
<DrawerSystem>
<Id>1</Id>
<Name>Drawer_System_1</Name>
<Location>North Wall (2nd from left)</Location>
<Drawers>
<Drawer>
<Id>1-01</Id>
<Contents>Contents of Drawer 1-01</Contents>
</Drawer>
<Drawer>
<Id>1-02</Id>
<Contents>Contents of Drawer 1-02</Contents>
</Drawer>
</Drawers>
</DrawerSystem>
</DrawerSystems>
</LegoElementsData>
然后,你可以在代码中创建一个匹配的数据结构,比如这个:
Public Class LegoElementsData
Public Property DrawerSystems() As List(Of DrawerSystem)
Get
Return _drawerSystems
End Get
Set(ByVal value As List(Of DrawerSystem))
_drawerSystems = value
End Set
End Property
Private _drawerSystems As List(Of DrawerSystem)
End Class
Public Class DrawerSystem
Public Property Id() As String
Get
Return _id
End Get
Set(ByVal value As String)
_id = value
End Set
End Property
Private _id As String
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Private _name As String
Public Property Location() As String
Get
Return _location
End Get
Set(ByVal value As String)
_location = value
End Set
End Property
Private _location As String
Public Property Drawers() As List(Of Drawer)
Get
Return _drawers
End Get
Set(ByVal value As List(Of Drawer))
_drawers = value
End Set
End Property
Private _drawers As List(Of Drawer)
Public Overrides Function ToString() As String
Return _name
End Function
End Class
Public Class Drawer
Public Property Id() As String
Get
Return _id
End Get
Set(ByVal value As String)
_id = value
End Set
End Property
Private _id As String
Public Property Contents() As String
Get
Return _contents
End Get
Set(ByVal value As String)
_contents = value
End Set
End Property
Private _contents As String
Public Overrides Function ToString() As String
Return _id & " - " & _ contents
End Function
End Class
然后,让你的生活更轻松,我建议你做的是简化的过程有点自己的序列化器类,如:
Public Class SimpleXmlSerializer
Public Function Serialize(ByVal objectToSerialize As Object) As String
Dim serializer As XmlSerializer = New XmlSerializer(objectToSerialize.GetType())
Using stream As MemoryStream = New MemoryStream()
Dim namespaces As XmlSerializerNamespaces = New XmlSerializerNamespaces()
namespaces.Add("", "")
serializer.Serialize(stream, objectToSerialize, namespaces)
Using reader As StreamReader = New StreamReader(stream)
stream.Position = 0
Return reader.ReadToEnd()
End Using
End Using
End Function
Public Function DeSerialize(Of T)(ByVal serializedObject As String) As T
Dim serializer As XmlSerializer = New XmlSerializer(GetType(T))
Using reader As StringReader = New StringReader(serializedObject)
Return CType(serializer.Deserialize(reader), T)
End Using
End Function
End Class
然后,当你加载数据,你可以简单地做这样的事情:
Public Class My_LEGO_Elements
Private Sub My_LEGO_Elements_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim serializer As New SimpleXmlSerializer()
Dim data As LegoElementsData = serializer.DeSerialize(Of LegoElementsData)(File.ReadAllText("C:\Users\Steven\Documents\Visual Studio 2012\Projects\My_LEGO_Elements\My_LEGO_Elements\Drawer_Systems_3.xml"))
ListBox1.Items.AddRange(data.DrawerSystems.ToArray())
End Sub
Private Sub ListBox1_SelectedValueChanged(ByVal sender As Object, ByVal e As EventArgs) Handles ListBox1.SelectedValueChanged
Dim drawerSystem As DrawerSystem = CType(ListBox1.SelectedItem, DrawerSystem)
Label1.Text = drawerSystem.Id
Label2.Text = drawerSystem.Location
Label3.Text = drawerSystem.Name
ListBox2.Items.Clear()
ListBox2.Items.AddRange(drawerSystem.Drawers.ToArray())
End Sub
End Class
谢谢您的回答。但是,这似乎并不适合我。 (Visual Studio 2012 RC显示SelectNode方法的错误。)如何从TreeNode.Tag属性读取数据? – 2012-07-12 19:29:39
@ user1517987我更新了我的答案,以修复我的错误并更清楚地解释标签的含义。 – 2012-07-12 19:36:04
为答谢新的信息,但我不知道在哪里或如何把它放在我的代码。我只是将我的代码添加到我的问题中以供参考。 – 2012-07-12 22:57:47