0

示例 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 节点的值?

我已经用我的 XML 文件填充了 TreeView 控件,并且我想在控件中选择它们时检索节点和子节点之间的某些值(作为字符串)。

我的预期结果

如果我选择 Drawer_System_1 节点或任何子节点,我想检索 DrawerSystemID、DrawerSysName 和 DrawerSysLocation 节点之间的值。

如果我选择 Drawer 节点或任何子节点,我想保留前面提到的值并检索 DrawerID 和 Contents 节点的值。

每个节点的值应该显示在单独的标签中,但如果在多行文本框(或标签)中显示我请求的数据更容易,那也可以。

笔记

我正在使用 VB.NET,但是如果您能想到 C# 中的解决方案,那也很好——我应该能够使用在线转换器将答案转换为 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 中。

4

1 回答 1

0

听起来像是一种奇怪的方法。我想如果您将 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

然后,当您为抽屉系统创建一个“TreeNode”时,您可以像这样设置它的标签:

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

我不明白为什么需要在 TreeView 的同一层次结构中显示 XML 中的所有元素。一个简单的抽屉系统列表似乎就足够了。Then when an item in the list was selected, you could show all the details about that drawer system in other controls. 此外,我建议不要尝试循环遍历 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
于 2012-07-12T12:11:15.440 回答