【问题标题】:Using LINQ to Parse XML Document with Namespace in Root Element使用 LINQ 解析带有根元素中命名空间的 XML 文档
【发布时间】:2018-04-08 01:32:35
【问题描述】:

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

<?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>

我编写了以下函数来使用 LINQ 返回一个字符串

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

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

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

<Message> 

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

returnValue = ID1:1871598417 | ID2: BE9432042-1234 |名称:主页小部件

我有以下问题:

  1. 当 xmlns 是根元素的一部分时,我需要在代码或 XPath 表达式中添加什么。

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

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

感谢大家的投入、时间和帮助。

谢谢

朱泽

【问题讨论】:

    标签: .net xpath linq-to-xml


    【解决方案1】:
    1. 你的问题是你没有给你的命名空间命名。 例如:
      &lt;Message xmlns:name="http://www.myurl.com/Product" version="010" release="006"&gt;.

      当您不为命名空间使用自定义名称时,您必须使用整个命名空间作为标识符。

      这是没有自定义名称的 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 而不是链接元素,这些元素可能在功能中的任何一个都可能最终为空。

    我希望我有所帮助。如果有任何问题,请随时提出,我会尽力解释。

    谢谢,

    编辑:

    当您想使用命名空间查找 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
    

    【讨论】:

    • 我从外部源接收文件,所以我无法控制它。我通过尝试将命名空间传递给“{myrul.com/Product\}Body”之类的后代来尝试您的建议,但仍然得到一个空白的返回值。你能提供示例代码来澄清一下吗?
    • 当我发布时,它似乎正在删除 www.myurl.com/Product 前面的 http://
    • 对 Null 条件运算符的尝试建议它仍然给了我 NullReferenceException 错误
    • 我知道每个子元素都是该命名空间的一部分,但是如何将其传递给后代以查询元素
    • 感谢您的代码,我能够理解您的想法,甚至添加了一个可能存在或可能不存在的元素,它返回正确的值。我正在发布更新的工作功能以供其他人受益。不确定格式将如何。但它来了
    猜你喜欢
    • 1970-01-01
    • 2012-09-27
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多