使用XElement和.Element查询XML

时间:2017-05-05 01:53:09

标签: xml vb.net

为一个非常初学的问题道歉;我非常擅长将VB与XML结合使用,并需要一些指导才能达到一定的理解力。

给出以下描述各种糖果的XML:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <Candy ID="MnMs">
    <Form ID="tablet" Name="Tablet">
      <Component ID="shell" Ingredients="sugar"/>
      <Component ID="filling" Ingredients="chocolate"/>
    </Form>
    <Form ID="oblong">
      <Component ID="shell" Ingredients="sugar"/>
      <Component ID="filling" Ingredients="chocolate"/>
      <Component ID="center" Ingredients="nut"/>
    </Form>
  </Candy>
  <Candy ID="LBalls">
    <Form ID="sphere">
      <Component ID="shell" Ingredients="chocolate"/>
      <Component ID="filling" Ingredients="chocolate ganache"/>
    </Form>
  </Candy>
  <Candy ID="RPieces">
    <Form ID="tablet">
      <Component ID="shell" Ingredients="sugar"/>
      <Component ID="filling" Ingredients="peanut butter ganache"/>
    </Form>
  </Candy>
</xs:schema>

(注意使用ID而不是更典型的(推荐?)id。)

如何在VB中访问Ingredients RPieces / tablet / filling的<Component>属性?具体来说,这一行:

<Component ID="filling" Ingredients="peanut butter ganache"/>

我的VB功能如下;我对如何管理身份感到困惑,特别是考虑到属性为IDid

Imports System.IO
Imports System.Xml
...
Function CandyFetch(ByVal candyId As String, ByVal formId As String, ByVal compId As String, ByVal attrId As String, Optional ByVal docPath As String = "Candies.xml") As String
    Const ID = "ID"
    Dim result = ""
    docPath = docPath.Trim()
    If Not File.Exists(docPath) Then docPath = AppDomain.CurrentDomain.BaseDirectory + docPath
    For Each bonbon In XElement.Load(docPath).Elements("Candy")
        If bonbon.Attribute(ID).Value = candyId Then
            For Each form In bonbon.Elements("Form")
                If form.Attribute(ID).Value = formId Then
                    For Each component In form.Elements("Component")
                        If component.Attribute(ID).Value = compId Then
                            result = component.Attribute(attrId).Value
                            Exit For
                        End If
                    Next
                End If
            Next
        End If
    Next
    Return result
End Function

谢谢。

打桩,有没有更简单的方法使用LinqToXml来完成这个,而不必迭代XML元素?

2 个答案:

答案 0 :(得分:1)

我建议使用XPATH查询:

Dim filename As String = "C:\Junk\example.xml"
Dim xdc As New XmlDocument
xdc.Load(filename)
Dim nsm As New XmlNamespaceManager(xdc.NameTable)
nsm.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema")
Dim strXPATH As String = "/xs:schema/Candy[@ID=""RPieces""]/Form/Component[@ID=""filling""]/@Ingredients"
MsgBox(strXPATH & "=" & vbCrLf &
       xdc.DocumentElement.SelectSingleNode(strXPATH, nsm).InnerText)

答案 1 :(得分:1)

使用LINQ to Xml,它可以如下所示

Dim doc As XDocument = XDocument.Load(docPath)
Dim value = doc.Descendants("Candy").
                Where(Function(candy) candy.Attribute("ID").Value = "RPieces").
                SelectMany(Function(candy) candy.Elements("Form")).
                Where(Function(form) form.Attribute("ID").Value = "tablet").
                SelectMany(Function(form) form.Elements("Component")).
                Where(Function(component) component.Attribute("ID").Value = "filling").
                Select(Function(component) component.Attribute("Ingredients").Value).
                FirstOrDefault()

通过使用具有Xml Axis属性的LINQ to Xml,您可以简化代码投标 XML Attribute Axis Property (Visual Basic)

Dim doc As XDocument = XDocument.Load(docPath)
Dim value = doc...<Candy>.
               Where(Function(candy) candy.@<ID> = "RPieces").
               <Form>.
               Where(Function(form) form.@<ID> = "tablet").
               <Component>.
               Where(Function(component) component.@<ID> = "filling").
               Select(Function(component) component.@<Ingredients>).
               FirstOrDefault()

如果您将命名空间导入代码,您将获得Intellisense帮助以编写轴属性的elments / attirbutes名称

另一种方法是使用序列化,创建表示xml结构的类,然后你的代码将如下所示

Dim serializer As New XmlSerializer(GetType(YourRootClass))
Dim data As YourRootClass = Nothing
Using fileStream As New FileStream(docPath, FileMode.Open)
    data = serializer.Deserialize(fileStream)
End Using

Dim value = data.Candies.
                 Where(Function(candy) candy.ID = "RPieces").
                 SelectMany(Function(candy) candy.Forms).
                 Where(Function(form) form.ID = "tablet").
                 SelectMany(Function(form) form.Components).
                 Where(Function(component) component.ID = "filling").
                 Select(Function(component) component.Ingredients).
                 FirstOrDefault()