使用LINQ在根元素中使用命名空间解析XML文档

时间:2018-04-08 01:32:35

标签: .net xpath linq-to-xml

我有以下名为Example.xml的XML文件。请注意根元素Message中的命名空间规范(xmlns),因为下面的问题与此有关。

OrderedDict([('Adityam', "('34', '2018-04-27 00:00:00'),No IMDB Info Available"),
             ('Baazaar', "('60', '2018-05-01 00:00:00'),N/A"),
             ('102 Not Out', "('75', '2018-05-04 00:00:00'),N/A"),
             ('3 Dev', "('0', '2018-05-11 00:00:00'),No IMDB Info Available"),
             ('Arjun Patiala', "('0', '2018-09-13 00:00:00'),No IMDB Info Available"),
             ('Ajay Devgn – Luv Ranjan’s Next', "('63', '2018-10-19 00:00:00'),No IMDB Info Available"),
             ('2.0', "('84', '2019-01-01 00:00:00'),8.5")])

我编写了以下函数来使用LINQ

返回一个字符串
<?xml version="1.0" encoding="utf-8" ?>
<Message xmlns="http://www.myurl.com/Product" version="010" release="006">
   <Header>
      <To Qualifier="P" />
      <From Qualifier="D" />
      <MessageID>f244251a8c6c4070</MessageID>
      <SentTime>2018-03-21T22:01:16.70Z</SentTime>
   </Header>
   <Body>
      <Product>
         <Description>
            <Identification>
               <ID1>1871598417</ID1>
               <ID2>BE9432042-1234</ID2>
            </Identification>
            <Type>
               <Name>Home Widget</Name>
               <Category>Residential</Category>
            </Type>
         </Description>
      </Product>
   </Body>
</Message>

我遇到的问题是上述XML文件的返回值为空。

当我将根元素更改为仅如下所示:

Public Function GetProductDetail() As String
    Dim xDoc As XDocument = Nothing
    Dim returnValue As String = ""

    Using xr As XmlReader = XmlReader.Create("C:\Automation\Example.xml")
        xDoc = XDocument.Load(xr)

        Dim query = From t In xDoc.Descendants("Body")
                    Select New With {Key _
                        .ID1 = t.Element("Product").Element("Description").Element("Identification").Element("ID1").Value,
                        .ID2 = t.Element("Product").Element("Description").Element("Identification").Element("ID2").Value,
                        .Name = t.Element("Product").Element("Description").Element("Type").Element("Name").Value}

        For Each item In query
            returnValue = $"ID1: {item.ID1} | ID2: {item.ID2} | Name: {item.Name}"
        Next

    End Using

    Return returnValue
End Function

(即删除包括xmlns = ....在内的所有内容)我得到正确的返回值

returnValue = ID1:1871598417 | ID2:BE9432042-1234 |名称:家庭小工具

我有以下问题:

  1. 当xmlns是根元素的一部分时,我需要添加到我的代码或XPath Expression中。

  2. 有时XML文件可能不包含ID2元素。如何在LINQ查询中检查元素是否存在,或者甚至可以使用LINQ。

  3. 如果这与LINQ不合适,有人可以提供有关如何完成此操作的代码。

  4. 感谢每个人的投入,时间和帮助。

    由于

    Juzer

1 个答案:

答案 0 :(得分:0)

  1. 问题是您没有为命名空间命名。 例如:
    <Message xmlns:name="http://www.myurl.com/Product" version="010" release="006">

    如果不为命名空间使用自定义名称,则必须使用整个命名空间作为标识符。

    这是没有自定义名称的Body的名称 {{http://www.myurl.com/Product}Body}这是自定义名称{Body}(现在您将会问为什么元素正文的名称上没有前面的{name:Body},因为它没有任何命名影响)

  2. 您可以使用Null条件运算符 例如:t.Element("Product").Element("Description").Element("Identification").Element("ID1")?.Value

  3. 虽然这不是一个答案LINQ基本上是一种做复杂的foreach的方法。所以我唯一能做到的就是使用XPath而不是链接元素中的元素,其中任何一个元素都可能最终为空。

  4. 我希望我帮助过。如果出现任何问题,请随时提出,我会尝试解释。

    谢谢,

    修改

    如果要使用命名空间查找xml节点,可以使用此类代码。 (如果我做错了,请饶恕我,我是C#Dev而不是Visual Basic)

    Dim nameSpace As xDoc.Root.GetDefaultNamespace()?.NamespaceName
    Dim body As xDoc.Descendants(XName.Get("Body", nameSpace))
    Dim productXName As XName.Get("Product", nameSpace)
    Dim descriptionXName As XName.Get("Description", nameSpace)
    Dim identificationXName As XName.Get("Identification", nameSpace)
    Dim id1XName As XName.Get("ID1", nameSpace)
    Dim id2XName As XName.Get("ID2", nameSpace)
    Dim typeXName As XName.Get("Type", nameSpace)
    Dim nameXName As XName.Get("Name", nameSpace)
    Dim query As From t In body
                select New With {Key _                        
                            .ID1 = t.Element(productXName).Element(descriptionXName).Element(identificationXName).Element(id1XName)?.Value,
                            .ID2 = t.Element(productXName).Element(descriptionXName).Element(identificationXName).Element(id2XName)?.Value,
                            .Name = t.Element(productXName).Element(descriptionXName).Element(typeXName).Element(nameXName)?.Value}
    

    '更新了工作VB.Net代码

    Public Function GetProductDetail() As String
        Dim xDoc As XDocument = Nothing
        Dim returnValue As String = ""
    
        Using xr As XmlReader = XmlReader.Create("C:\Automation\Example.xml")
            xDoc = XDocument.Load(xr)
            Dim xn = xDoc.Root.GetDefaultNamespace()?.NamespaceName
            Dim body = xDoc.Descendants(XName.Get("Body", xn))
            Dim productXName = XName.Get("Product", xn)
            Dim descriptionXName = XName.Get("Description", xn)
            Dim identificationXName = XName.Get("Identification", xn)
            Dim id1XName = XName.Get("ID1", xn)
            Dim id2XName = XName.Get("ID2", xn)
            Dim typeXName = XName.Get("Type", xn)
            Dim nameXName = XName.Get("Name", xn)
            ' Name1 May or Maynot exist in the XML file
            Dim nameXName1 = XName.Get("Name1", xn)
    
            ' DT May or May not Exist in recived XML File
            Dim query = From t In body
                        Select New With {Key _
                            .ID1 = t.Element(productXName).Element(descriptionXName).Element(identificationXName).Element(id1XName)?.Value,
                            .ID2 = t.Element(productXName).Element(descriptionXName).Element(identificationXName).Element(id2XName)?.Value,
                            .Name = t.Element(productXName).Element(descriptionXName).Element(typeXName).Element(nameXName)?.Value,
                            .DT = t.Element(productXName).Element(descriptionXName).Element(typeXName).Element(nameXName1)?.Value}
    
    
            For Each item In query
                returnValue = $"ID1: {item.ID1} | ID2: {item.ID2} | Name: {item.Name} | DT: {item.DT} "
            Next
        End Using
        Return returnValue
    End Function