在值中搜索字符串并在 LINQ 中获取属性值到 VB.NET 中的 XML

search string in value and get attribute value in LINQ to XML in VB.NET

我有一个 XML 文件,我想使用 Contains 命令搜索“val”的值并获取其“索引”属性以及“目录名称”属性。

<list>
    <catalog index="1" name="n1">
        <val index="1">sample text 1</val>
        <val index="2">sample text 2</val>
        <val index="3">sample text 3</val>
    </catalog>
    <catalog index="2" name="n2">
        <val index="1">sample text 0</val>
        <val index="2">sample text 2</val>
        <val index="3">sample text 3</val>
        <val index="4">sample text 1</val>
        <val index="5">sample text 5</val>
        <val index="6">sample text 6</val>
    </catalog>
    <catalog index="3" name="n3">
        <val index="1">sample text 8</val>
        <val index="2">sample text 9</val>
        <val index="3">sample text 10</val>
    </catalog>
</list>

我用过

Dim xml_Doc = XDocument.Load(myPath & "list.Xml")

Dim search_result As IEnumerable(Of XElement)
search_result =
        (From c In xml_Doc.Descendants("catalog")
         Where c.Elements("val").Value.Contains("sample text 1")
         Select c.Elements("val").Attributes("index").ToString & c.Attribute("name").Value)

我该怎么做?

输出应该如下:

index:1 , name: n1
index:4 , name: n2

最简单的方法是对 c.Elements("val") 元素进行嵌套 From 查询,如下所示:

Dim sampleText = "sample text 1"
Dim search_result = 
    (From c In xml_Doc.Descendants("catalog")
    From v in c.Elements("val")
    Where v.Value.Contains(sampleText)
    Select New With {.index = v.Attribute("index").Value, .name = c.Attribute("name").Value })
    
For Each s In search_result
    Console.WriteLine("index:{0} , name:{1}", s.index, s.name)
Next

产生:

index:1 , name:n1
index:4 , name:n2
index:3 , name:n3

备注:

  • 这样做可以让您轻松过滤内部元素 v 的值,然后过滤 v 和外部元素的 select 属性c.

  • index:3 , name:n3 包含在结果中,因为此元素 sample text 10 的文本包含搜索字符串 sample text 1。如果您不想包含此元素,请更改 Where 子句以使用相等性:

     Dim search_result = 
         (From c In xml_Doc.Descendants("catalog")
         From v in c.Elements("val")
         Where v.Value = sampleText
         Select New With {.index = v.Attribute("index").Value, .name = c.Attribute("name").Value })
    

小提琴演示 here and here

免责声明:我喜欢 XmlSerialization。强类型和可重用对象。我会首先通过创建一些 类 来将文件序列化为

来解决这个问题
Imports System.IO
Imports System.Xml.Serialization
<XmlRoot("list")>
Public Class List
    <XmlElement("catalog")>
    Public Property Catalogs As List(Of Catalog)
End Class

Public Class Catalog
    <XmlElement("val")>
    Public Property Vals As List(Of Val)
    <XmlAttribute("index")>
    Public Property Index As Integer
    <XmlAttribute("name")>
    Public Property Name As String
End Class

Public Class Val
    <XmlAttribute("index")>
    Public Property Index As Integer
    <XmlText>
    Public Property Text As String
End Class

然后反序列化文件

Dim list As List
Dim serializer As New XmlSerializer(GetType(List))
Using sr As New StreamReader("list.xml")
    list = CType(serializer.Deserialize(sr), List)
End Using

现在您的 xml 在 .NET 类 中,您可以使用 LINQ 来获得您想要的东西

Dim searchString = "sample text 1"
Dim catalogs As New List(Of Catalog)()
For Each catalog In list.Catalogs
    Dim vals = catalog.Vals.Where(Function(val) val.Text = searchString)
    For Each val In vals
        catalogs.Add(New Catalog() With {.Vals = {val}.ToList(), .Name = catalog.Name, .Index = catalog.Index})
    Next
Next
Dim search_results = catalogs.SelectMany(Function(c) c.Vals.Select(Function(v) $"index:{v.Index}, name: {c.Name}"))
For Each search_result In search_results
    Console.WriteLine(search_result)
Next

输出:

index:1, name: n1
index:4, name: n2

它变得有点笨拙,因为您想要 n 对 m 关系中的 m 个项目(n 个目录和 m 个值),因此我们使用 SelectMany 将目录投影到多个值中。但是对象 list 拥有您可以用于其他目的的所有数据。

如另一个答案所述,您正在搜索包含“示例文本 1”但 returns“示例文本 10”的字符串,并且根据您想要的输出,您应该搜索完全匹配。