C# 在XML中查找值

C# 在XML中查找值,c#,xml,linq-to-xml,C#,Xml,Linq To Xml,我将一个xml文件加载到一个XDocument中,需要从中提取一个值,但我不确定最好的方法。我想到的大多数东西似乎都有些过火,或者没有很好地利用xml规则。我有以下xml片段: <entry> <observation classCode="OBS" moodCode="EVN"> <templateId root="2.16.840.1.113883.10.20.6.2.12" /> <code co

我将一个xml文件加载到一个XDocument中,需要从中提取一个值,但我不确定最好的方法。我想到的大多数东西似乎都有些过火,或者没有很好地利用xml规则。我有以下xml片段:

    <entry>
      <observation classCode="OBS" moodCode="EVN">
        <templateId root="2.16.840.1.113883.10.20.6.2.12" />
        <code code="121070" codeSystem="1.2.840.10008.2.16.4" codeSystemName="DCM" displayName="Findings">
        </code>
        <value xsi:type="ED">
          <reference value="#121071">
          </reference>
        </value>
      </observation>
    </entry>


可以有任意数量的
节点,它们都将遵循类似的模式。
templateId
元素的
root
属性下的值包含一个已知的UID,该UID将此条目标识为我想要的条目。我需要得到参考值

我的想法是找到正确的templateID节点,返回到观察节点,找到
,然后获得参考值。这似乎过于复杂,我想知道是否有其他方法可以做到这一点

编辑


我接收的xml有时可以将xml嵌套在相同的节点名下。换句话说,
可能位于另一个名为

的节点下,是否需要以下帮助

   XDocument xdoc = GetYourDocumentHere();
   var obsvlookfor =
       xdoc.Root.Descendants("observation")
           .SingleOrDefault(el => 
                el.Element("templateId")
                    .Attribute("root").Value == "root value to look for");

   if (obsvlookfor != null)
   {
       var reference = obsvlookfor
           .Element("value")
           .Element("reference").Attribute("value").Value;
   }
我的想法如下:

  • 拉出文档中的所有观察元素
  • 查找观测值的
    templateId
    元素具有您要查找的
    root
    属性的唯一一个(或null)
  • 如果找到该观察元素,则针对
    value
    元素下的
    reference
    元素拉出
    value
    属性

  • 按照下面的思路做一些事情会有帮助吗

       XDocument xdoc = GetYourDocumentHere();
       var obsvlookfor =
           xdoc.Root.Descendants("observation")
               .SingleOrDefault(el => 
                    el.Element("templateId")
                        .Attribute("root").Value == "root value to look for");
    
       if (obsvlookfor != null)
       {
           var reference = obsvlookfor
               .Element("value")
               .Element("reference").Attribute("value").Value;
       }
    
    我的想法如下:

  • 拉出文档中的所有观察元素
  • 查找观测值的
    templateId
    元素具有您要查找的
    root
    属性的唯一一个(或null)
  • 如果找到该观察元素,则针对
    value
    元素下的
    reference
    元素拉出
    value
    属性

  • 您可能必须在LINQ中包含名称空间。要检索,请执行以下操作:

    XNamespace ns = xdoc.Root.GetDefaultNamespace();
    
    然后在你的linq中:

    var obsvlookfor = xdoc.Root.Descendants(ns + "observation")
    

    我知道我曾经在没有这个的情况下检索数据时遇到了一些问题。不要说这是一个需要记住的问题,特别是当您的XML文件非常深入时。

    您可能必须在LINQ中包含名称空间。要检索,请执行以下操作:

    XNamespace ns = xdoc.Root.GetDefaultNamespace();
    
    然后在你的linq中:

    var obsvlookfor = xdoc.Root.Descendants(ns + "observation")
    

    我知道我曾经在没有这个的情况下检索数据时遇到了一些问题。不要说这是一个需要记住的问题,特别是当您的XML文件非常深入时。

    您有问题,因为您的文档使用名称空间,而您的查询缺少名称空间

    首先,您必须在XML中的某个地方找到
    xsi
    名称空间声明(可能在最顶层的元素中)

    看起来是这样的:

    xmlns:xsi="http://test.namespace"
    
    然后,获取名称空间Uri并根据其值创建
    XNamespace
    实例:

    var xsi = XNamespace.Get("http://test.namespace");
    
    并在查询中使用
    xsi
    变量:

    var query = from o in xdoc.Root.Element("entries").Elements("entry").Elements("observation")
                let tId = o.Element("templateId")
                where tId != null && (string)tId.Attribute("root") == "2.16.840.1.113883.10.20.6.2.12"
                let v = o.Element("value")
                where v != null && (string)v.Attribute(xsi + "type") != null
                let r = v.Element("reference")
                where r != null
                select (string)r.Attribute("value");
    
    var result = query.FirstOrDefault();
    
    我已经针对以下XML结构对其进行了测试:

    <root xmlns:xsi="http://test.namespace">
      <entries>
        <entry>
          <observation classCode="OBS" moodCode="EVN">
            <templateId root="2.16.840.1.113883.10.20.6.2.12" />
            <code code="121070" codeSystem="1.2.840.10008.2.16.4" codeSystemName="DCM" displayName="Findings">
            </code>
            <value xsi:type="ED">
              <reference value="#121071">
              </reference>
            </value>
          </observation>
        </entry>
      </entries>
    </root>
    

    要匹配XML结构中的
    元素,您会遇到问题,因为您的文档使用名称空间,而您的查询缺少名称空间

    首先,您必须在XML中的某个地方找到
    xsi
    名称空间声明(可能在最顶层的元素中)

    看起来是这样的:

    xmlns:xsi="http://test.namespace"
    
    然后,获取名称空间Uri并根据其值创建
    XNamespace
    实例:

    var xsi = XNamespace.Get("http://test.namespace");
    
    并在查询中使用
    xsi
    变量:

    var query = from o in xdoc.Root.Element("entries").Elements("entry").Elements("observation")
                let tId = o.Element("templateId")
                where tId != null && (string)tId.Attribute("root") == "2.16.840.1.113883.10.20.6.2.12"
                let v = o.Element("value")
                where v != null && (string)v.Attribute(xsi + "type") != null
                let r = v.Element("reference")
                where r != null
                select (string)r.Attribute("value");
    
    var result = query.FirstOrDefault();
    
    我已经针对以下XML结构对其进行了测试:

    <root xmlns:xsi="http://test.namespace">
      <entries>
        <entry>
          <observation classCode="OBS" moodCode="EVN">
            <templateId root="2.16.840.1.113883.10.20.6.2.12" />
            <code code="121070" codeSystem="1.2.840.10008.2.16.4" codeSystemName="DCM" displayName="Findings">
            </code>
            <value xsi:type="ED">
              <reference value="#121071">
              </reference>
            </value>
          </observation>
        </entry>
      </entries>
    </root>
    

    匹配XML结构中的
    元素。

    感谢您的回复。它看起来很棒,我认为,在正常情况下,这本可以做到。然而,我得到了一个空回。我相信这是因为观察节点嵌套在另一个观察节点下,所以它找到了根观察,而不是嵌套的。我本应该在我的问题中提出这一点,但我没有注意到。我仔细研究了您建议的代码,发现即使我更改了值以匹配外部观察节点,obsvlookfor仍然为null。@Tim观察值是如何嵌套在XML中的?因为这将影响您需要如何建立查询。我建议您将查询分解为若干部分,并在调试器的每个阶段检查返回的结果,以帮助您确定所需的最佳查询。嵌套观察可能会使查询更难管理,但并非不可能。感谢您的回复。它看起来很棒,我认为,在正常情况下,这本可以做到。然而,我得到了一个空回。我相信这是因为观察节点嵌套在另一个观察节点下,所以它找到了根观察,而不是嵌套的。我本应该在我的问题中提出这一点,但我没有注意到。我仔细研究了您建议的代码,发现即使我更改了值以匹配外部观察节点,obsvlookfor仍然为null。@Tim观察值是如何嵌套在XML中的?因为这将影响您需要如何建立查询。我建议将查询分解为若干部分,并在调试器的每个阶段检查返回的结果,以帮助您确定所需的最佳查询。嵌套观察可能会使查询更难管理,但并非不可能。您必须显示整个XML输入,因为在示例部分中使用了命名空间
    xsi
    ,但我们不知道它是如何声明的。您必须显示整个XML输入,因为在示例部分中使用了命名空间
    xsi
    ,但我们不知道它是如何声明的。