使用LINQ读取XML数据,同名的多个元素 VB[英] Reading XML data using LINQ, multiple elements with the same name VB

本文是小编为大家收集整理的关于使用LINQ读取XML数据,同名的多个元素 VB的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我有一个包含多个同名节点的 xml

<?xml version="1.0" encoding="UTF-8"?>
<Versions>
    <Version>
        <Trunk>GapGun Software Version 7.1</Trunk>
            <Branch>.142</Branch>
            <Branch>.145</Branch>
            <Branch>.148</Branch>
            <Branch>.153</Branch>
            <Branch>.176</Branch>
    </Version>
    <Version>
        <Trunk>GapGun Software Version 7.2</Trunk>
            <Branch>.142</Branch>
            <Branch>.145</Branch>
            <Branch>.148</Branch>
            <Branch>.153</Branch>
            <Branch>.176</Branch>
    </Version>
</Versions> 

我需要在使用 Trunk 作为查询过滤时填充一个组合框到目前为止我有这个代码

Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim xelement As XElement = XElement.Load("F:\Test.xml")
    Dim Versions As IEnumerable(Of XElement) = xelement.Elements()
    For Each Version In Versions
        Console.WriteLine(Version.Element("Trunk").Value)
        ComboBox1.Items.Add(Version.Element("Trunk").Value)
    Next Version
End Sub

Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
    Dim xelement As XElement = XElement.Load("F:\Test.xml")
    Dim name =
        From nm In xelement.Elements("Version")
        Where CStr(nm.Element("Trunk")) = ComboBox1.Text
        Select nm
    For Each xEle As XElement In name
        Console.WriteLine(xEle)
        ComboBox2.Items.Add(xEle.Element("Branch").Value)
    Next xEle
End Sub
End Class

这可行,但只返回第一个分支,请帮助,我是一个完整的新手!

推荐答案

您的问题是您使用方法 XElement.Element 将返回给定名称的一个(第一个)元素.
来自文档:获取第一个(按文档顺序)具有指定 XName 的子元素.

您需要更改代码以循环所有"分支"元素,您可以使用 ComboBox.Items.AddRange 方法添加所有元素

Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) _
        Handles ComboBox1.SelectedIndexChanged

    Dim xelement As XElement = XElement.Load("F:\Test.xml")
    Dim name =
        From nm In xelement.Elements("Version")
        Where CStr(nm.Element("Trunk")) = ComboBox1.Text
        Select nm

    For Each xEle As XElement In name
        Dim branches = xEle.Elements("Branch").Select(Function(el) el.Value).ToArray()

        Console.WriteLine(xEle)
        ComboBox2.Items.AddRange(branches)
    Next
End Sub

为了使代码更简单并仅加载文件 - 您可以引入包含所有必需数据的 Version 类.
然后您不需要搜索正确的主干,并且将使用已经存在的分支.

Public Class Version
    Public Property Trunk As String
    Public Property Branches As List(Of String)
End Class

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim xelement As XElement = XElement.Load("F:\Test.xml")

    ' Create collection of versions
    Dim versions = _ 
        xelement.Elements().
                 Select(Function(version)
                           Return New Version With
                           {
                               .Trunk = version.Element("Trunk").Value
                               .Branches = version.Elements("Branch").
                                                   Select(Function(el) el.Value)
                           }
                        End Function)

    ' Bind collection of versions to ComboBox
    ' Name of property which will be used as displayed text
    ComboBox1.DisplayMember = "Trunk"
    ComboBox1.DataSource = versions
End Sub

然后当用户选择树干填充分支组合框会简单得多

Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) _ 
        Handles ComboBox1.SelectionChangeCommitted

    Dim comboBox = DirectCast(sender, ComboBox)
    Dim selectedVersion = DirectCast(comboBox.SelectedItem, Version)

    ComboBox2.DataSource = selectedVersion.Branches
End Sub

本文地址:https://www.itbaoku.cn/post/1557219.html

问题描述

I have an xml with multiple nodes of the same name

<?xml version="1.0" encoding="UTF-8"?>
<Versions>
    <Version>
        <Trunk>GapGun Software Version 7.1</Trunk>
            <Branch>.142</Branch>
            <Branch>.145</Branch>
            <Branch>.148</Branch>
            <Branch>.153</Branch>
            <Branch>.176</Branch>
    </Version>
    <Version>
        <Trunk>GapGun Software Version 7.2</Trunk>
            <Branch>.142</Branch>
            <Branch>.145</Branch>
            <Branch>.148</Branch>
            <Branch>.153</Branch>
            <Branch>.176</Branch>
    </Version>
</Versions> 

I need to populate a combo box when filtered using the Trunk as a query so far i have this code

Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim xelement As XElement = XElement.Load("F:\Test.xml")
    Dim Versions As IEnumerable(Of XElement) = xelement.Elements()
    For Each Version In Versions
        Console.WriteLine(Version.Element("Trunk").Value)
        ComboBox1.Items.Add(Version.Element("Trunk").Value)
    Next Version
End Sub

Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
    Dim xelement As XElement = XElement.Load("F:\Test.xml")
    Dim name =
        From nm In xelement.Elements("Version")
        Where CStr(nm.Element("Trunk")) = ComboBox1.Text
        Select nm
    For Each xEle As XElement In name
        Console.WriteLine(xEle)
        ComboBox2.Items.Add(xEle.Element("Branch").Value)
    Next xEle
End Sub
End Class

This works but only returns the first branch please help, i am a complete novice!

推荐答案

Your problem is that you using method XElement.Element which will return one(first) element of given name.
From docs: Gets the first (in document order) child element with the specified XName.

You need change code to loop all "Branch" elements and you can add all of them by using ComboBox.Items.AddRange method

Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) _
        Handles ComboBox1.SelectedIndexChanged

    Dim xelement As XElement = XElement.Load("F:\Test.xml")
    Dim name =
        From nm In xelement.Elements("Version")
        Where CStr(nm.Element("Trunk")) = ComboBox1.Text
        Select nm

    For Each xEle As XElement In name
        Dim branches = xEle.Elements("Branch").Select(Function(el) el.Value).ToArray()

        Console.WriteLine(xEle)
        ComboBox2.Items.AddRange(branches)
    Next
End Sub

To make code little bid simpler and load files only ones - you can introduce Version class which contains all required data.
Then you don't need to search for correct trunk and will use already existing branches.

Public Class Version
    Public Property Trunk As String
    Public Property Branches As List(Of String)
End Class

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim xelement As XElement = XElement.Load("F:\Test.xml")

    ' Create collection of versions
    Dim versions = _ 
        xelement.Elements().
                 Select(Function(version)
                           Return New Version With
                           {
                               .Trunk = version.Element("Trunk").Value
                               .Branches = version.Elements("Branch").
                                                   Select(Function(el) el.Value)
                           }
                        End Function)

    ' Bind collection of versions to ComboBox
    ' Name of property which will be used as displayed text
    ComboBox1.DisplayMember = "Trunk"
    ComboBox1.DataSource = versions
End Sub

Then when user selects trunk populating branches combobox will be much simpler

Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) _ 
        Handles ComboBox1.SelectionChangeCommitted

    Dim comboBox = DirectCast(sender, ComboBox)
    Dim selectedVersion = DirectCast(comboBox.SelectedItem, Version)

    ComboBox2.DataSource = selectedVersion.Branches
End Sub