【问题标题】:LINQ to XML: how do I get only direct descendants of an XElement?LINQ to XML:如何仅获取 XElement 的直接后代?
【发布时间】:2009-08-04 11:14:14
【问题描述】:
Dim xml = <Root>
            <Parent id="1">
              <Child>Thomas</Child>
            </Parent>
            <Parent id="2">
              <Child>Tim</Child>
              <Child>Jamie</Child>
            </Parent>
          </Root>

Dim parents = xml.Elements

在这种情况下,children 包括所有父元素和所有子元素。 只获取&lt;Root&gt; 的直系后代的最佳方式是什么?

我是否应该编写一个 LINQ 查询来选择 parent = &lt;Root&gt; 的元素?或者是否有一些我缺少的内置方法可以为我获取这个?

编辑:我在XElement.ElementsXElement.Descendants 之间有些混淆。正如 Ruben Bartelink 所指出的那样,XElement.Elements 会给我提供我想要的东西。

【问题讨论】:

  • 你可以编辑你最终使用的实际咒语吗?顺便说一句,请下载 LINQPAd 并尝试一下——它非常适合测试这样的东西。请参阅dimecasts.net/Casts/ByTag/LinqPad 中的示例

标签: .net xml vb.net linq-to-xml


【解决方案1】:

XElement.Elements 获取子元素的集合。比如……

var s = @"<root>
             <e1>
                 <e2>
                 </e2>
             </e1>
             <e1>
                 <e2>
                 </e2>
             </e1>
             <e1>
                 <e2>
                 </e2>
             </e1>
          </root>";

var doc = XElement.Load( new StringReader(s) );

Console.WriteLine( doc.Elements().Count() ); // 3
Console.WriteLine( doc.Descendants().Count()); //6

【讨论】:

    【解决方案2】:

    执行摘要 - 你想要:

    xml.Elements.Select(function(element) new XElement(element.Name,element.Attributes))
    

    第一个答案:

    XElement.Descendants,或者这是一个技巧问题? :PThere's an example of usage of Descendants here

    修改后的答案,谢谢 Tormod —— 确实感觉有些不对劲!:

    Elements 提供了您正在寻找的直接后代。后代给出了完整的层次结构[正如你所声称的元素所做的那样]。 (我链接到的示例清楚地说明了这一点。为混淆道歉!

    所以,最后,您正在寻找的是(这次是在 VB 中):

    Dim xml = <Root>
            <Parent id="1">
              <Child>Thomas</Child>
            </Parent>
            <Parent id="2">
              <Child>Tim</Child>
              <Child>Jamie</Child>
            </Parent>
          </Root>
    
    REM All nodes two levels down in the hierarchy
    Dim level2Nodes = xml.Elements.SelectMany(function(element) element.Elements)
    level2Nodes.Dump
    
    REM All Child nodes, no matter where they are:
    Dim children = xml.Descendants("Child")
    

    由于 REM 中涵盖的不同原因,每一个都会为您生成 3 个 ``` 元素。

    (在VB语句模式下将上面直接粘贴到LINQPad中)

    我现在知道什么可能让您感到困惑 - 当您使用 Elements 并在可视化器中查看它时,您仍然看到孩子:-

    Dim parents = xml.Elements
    

    如果你只想要实际的名字,你可以使用类似的东西:

    Dim parentNames = xml.Elements.Select(function(element) element.Name)
    

    请注意,在每种情况下,您都会得到两个结果。

    如果你真的想去掉孩子,你想:

    Dim parentElements = xml.Elements.Select(function(element) new XElement(element.Name,element.Attributes))
    

    您能否扩展您的问题以显示您真正在寻找什么?

    【讨论】:

    • Descendants() 方法获取所有后代,而不仅仅是直接后代。在这种情况下,“root”的后代也将包括所有子元素。
    • @Tormod,你确定吗?看到例子了吗?如果不是,后代和元素之间的区别是什么?
    【解决方案3】:

    使用 Linq 我们可以做到这一点。

    string s = "<Root><Parent id=\"1\"><Child>Thomas</Child></Parent><Parent id=\"2\"><Child>Tim</Child><Child>Jamie</Child></Parent></Root>";
    XDocument xdoc = XDocument.Parse(s);
    foreach (XElement DirectChild in xdoc.Descendants().Where(child => child.Parent == xdoc.Root))
    {
    //Do stuff here
    }
    

    希望这会有所帮助。谢谢。

    【讨论】:

      【解决方案4】:

      如果所有直系后代具有相同的已知元素名称,并且该元素名称不能出现在另一个级别,则可以使用 xml.Descendants("Parent")。

      【讨论】:

        【解决方案5】:

        为什么不使用 XPath?

        Dim myXML As var = New XmlDocument()
        myXML.Load(myXML.xml)
        
        For Each node As XmlNode In myXML.SelectNodes("//")
            Dim myVar As var = node.SelectSingleNode("Parent").InnerText
        Next
        

        加点盐,我刚刚将它从 C# 转换为 VB。

        【讨论】:

        • XLinq 做得非常简洁 [一旦人们克服了使用哪种方法的问题:P]
        • 很公平:P 我得研究一下,如果你们都转向 Xlinq,我猜 XPath 已经过时了!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多