【问题标题】:LINQ to XML filter descendants C#LINQ to XML 过滤后代 C#
【发布时间】:2014-06-18 12:12:37
【问题描述】:

我有第三方发送的 xml,我想对其进行验证。

XElement xTree = XElement.Parse(@"<Container>
    <TrackingReferences>
        <TrackingReference>
          <TrackingName>Donny</TrackingName>
          <TrackingCodes>
            <TrackingCode>
                <Name></Name>
            </TrackingCode>
            <TrackingCode>
                <Name>DisplayThis</Name>
            </TrackingCode>
            <TrackingCode>
                <Name></Name>
            </TrackingCode>
          </TrackingCodes>
        </TrackingReference>
      </TrackingReferences>
    </Container>");

IEnumerable<XElement> childList = xTree.Element("TrackingReferences").Descendants("TrackingReference").Where(
    tr => (
            tr.Element("TrackingName") != null && !tr.Element("TrackingName").IsEmpty && !String.IsNullOrEmpty(tr.Element("TrackingName").Value) &&
            tr.Descendants("TrackingCodes").Any(
                tc => tc.HasElements &&
                    tc.Elements("TrackingCode").Any(
                        code => code.Element("Name") != null && !code.Element("Name").IsEmpty && !String.IsNullOrEmpty(code.Element("Name").Value)
                    )
            )
    )
);

我不知道如何返回我想要的后代。

我遇到的问题是,当 TrackingCode 具有 Name 不为 null 或空的元素。

下面的例子返回:

<TrackingReference>
  <TrackingName>Donny</TrackingName>
  <TrackingCodes>
    <TrackingCode>
      <Name></Name>
    </TrackingCode>
    <TrackingCode>
      <Name>DisplayThis</Name>
    </TrackingCode>
    <TrackingCode>
      <Name></Name>
    </TrackingCode>
  </TrackingCodes>
</TrackingReference>

但是在这个例子中,我不希望返回第一个和第三个 TrackingCode 元素,只返回第二个,因为它有一个 Name 元素,像这样:

<TrackingReference>
      <TrackingName>Donny</TrackingName>
      <TrackingCodes>
        <TrackingCode>
          <Name>DisplayThis</Name>
        </TrackingCode>
      </TrackingCodes>
    </TrackingReference>

这是我第一次尝试对 XML 进行 LINQ 查询,因此,如果我以错误的方式处理此问题,将非常感谢任何有关如何使查询更简洁/高效的建议。

【问题讨论】:

  • 您真的想要修改版本的 TrackingReference 元素,还是对具有非空名称的 TrackingCode 元素序列感到满意?后者要简单得多。
  • 假设您想要一个修剪过的文档,Xsl 转换可能更适合这个问题?
  • @JonSkeet - 后者;一系列具有非空名称的 TrackingCode 元素,因此在上面的示例中,将只返回一个 TrackingCode 元素而不是三个 TrackingCode 元素(因为查询当前正在返回)。非常感谢。
  • @StuartLC - 我最终可能会选择 XSLT,但由于我没有做太多 LINQ to XML 我希望挑战能够更好地理解它

标签: .net xml linq xelement descendant


【解决方案1】:

好的,听起来你想要TrackingCode 元素而不是TrackingReference 元素,所以实际上很简单:

var query = doc.Descendants("TrackingReference")
               // TODO: Filter based on TrackingName if you want...
               .Descendants("TrackingCode")
               .Where(x => !string.IsNullOrEmpty((string) x.Element("Name"));

这使用了这样一个事实,即如果您使用null 操作数调用XElement 上的显式字符串转换将返回null

【讨论】:

  • 我一直在寻找 TrackingReference 元素,但它只有 TrackingCode 后代的名称非空。我编辑了问题以显示我希望返回的内容。理论上,原始 xml 中可能有许多 TrackingReference 元素,所以我想对所有元素运行过滤器。显式字符串转换的好技巧。感谢您的帮助
【解决方案2】:

以防万一您确实想考虑 xslt 解决方案,您可以使用身份转换消除空的 TrackingCodes 和 eat 空节点的模板:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" />
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="TrackingCode[not(Name)] | TrackingCode[Name='']"/>
</xsl:stylesheet>

XslCake fiddle here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    相关资源
    最近更新 更多