2012-07-12 174 views
0

示例XML如何同時檢索子節點和父節點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中。

回答

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 

然後,當你對一個抽屜系統創建一個'樹節點」,你可以設置是這樣的標籤:

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 
+0

謝謝您的回答。但是,這似乎並不適合我。 (Visual Studio 2012 RC顯示SelectNode方法的錯誤。)如何從TreeNode.Tag屬性讀取數據? – 2012-07-12 19:29:39

+0

@ user1517987我更新了我的答案,以修復我的錯誤並更清楚地解釋標籤的含義。 – 2012-07-12 19:36:04

+0

爲答謝新的信息,但我不知道在哪裏或如何把它放在我的代碼。我只是將我的代碼添加到我的問題中以供參考。 – 2012-07-12 22:57:47