LINQ to XML:如何选择下一个元素

Posted

技术标签:

【中文标题】LINQ to XML:如何选择下一个元素【英文标题】:LINQ to XML: How to select the next element 【发布时间】:2011-07-04 09:03:47 【问题描述】:

我有一个来自 iPhone 应用程序的 plist 文件。如下所示:

<plist version="1.0">
  <dict>
    <key>barcodes</key>
    <array>
      <string>JF893J89FJ-66666</string>
      <string>JF893J89FJ-55555</string>
    </array>
    <key>currentStep</key>
    <integer>1</integer>
    <key>dateFinished</key>
    <date>2010-05-10T18:33:25Z</date>
    <key>dateStarted</key>
    <date>2010-05-10T18:33:25Z</date>
    <key>description</key>
    <string>TEST</string>
    <key>geoRequired</key>
    <string>N</string>
    <key>inProgress</key>
    <string>N</string>
    <key>jobID</key>
    <integer>10085</integer>
    <key>jobSteps</key>
    <array>
      <dict>
        <key>label</key>
        <string>TEST</string>
        <key>response</key>
        <string>matt hudson</string>
        <key>stepID</key>
        <integer>1103</integer>
        <key>typeID</key>
        <integer>4</integer>
      </dict>
    </array>
  </dict>
</plist>

我需要在jobSteps之后获取数组。

到目前为止我有这个:

XDocument xml = XDocument.Load(rri.Response);

var q = from elements in xml.Descendants("plist").Descendants("dict")
        where elements.Value == "jobSteps"
        select elements;

但我需要在其中包含 jobSteps 的元素之后获取下一项。

【问题讨论】:

为什么不按名称获取&lt;array&gt; 节点? 【参考方案1】:

我并不完全清楚 Adam 的解决方案是否是您想要的,但如果不是,您可能需要查看 NextNode 属性:

获取该节点的下一个兄弟节点。

例如,打印数组元素:

using System;
using System.Linq;
using System.Xml.Linq;

class Test

    static void Main()
    
        XDocument doc = XDocument.Load("test.xml");
        foreach (var element in doc.Descendants("key")
                                   .Where(x => (string) x == "jobSteps"))
        
            Console.WriteLine(element.NextNode);
        
    

请注意,它会跳过元素之间的空格 - 但如果 与数组之间有任何文本,它将不起作用 - 所以你想要:

Console.WriteLine(element.NodesAfterSelf().OfType<XElement>().First());

【讨论】:

有很多很棒的答案,但我确实使用了 NextNode,这正是我想要的。 谢谢 - 在您发布之前不久,我的原始答案很明显是不够的。 +1 :) 乔恩,为了我的启迪,当你说 CW(element.NextNode) - 是否显示节点的 XML 值?我知道 XElement:XNode,我只是想知道它与节点相对于元素有什么用。 @Adam:它显示节点的ToString 方法返回的任何内容。对于文本节点,它是文本......对于一个元素,它是包括后代在内的完整元素。通常,使用 XElement 比使用 XNode 更容易,是的。【参考方案2】:

编辑

我相信这会让你得到 jobSteps 节点之后的元素:

XElement elementAfterJobsteps = xml.Descendants("plist").FirstOrDefault().Descendants("jobSteps").FirstOrDefault().ElementsAfterSelf().FirstOrDefault();

结束编辑

foreach (XElement El in xml.Descendants("plist")) 
        var localResults = 
            from elements in El.Descendants("dict")
            where elements.Value == "jobSteps"
            select elements;

       //process localResults 
 

或者,更简单,试试方法语法

 foreach (XElement El in xml.Descendants("plist")) 
    var localResults = El.Descendants("dict").Where(dict => dict.Value == "jobSteps");

    //process localResults 
 

【讨论】:

【参考方案3】:
var q = xml
        .Descendants("plist")
        .Descendants("dict")
        .Where(item => item.Value == "jobSteps")
        .Select(item => item.NextNode)
        .SingleOrDefault() // add this if you expect single match
        ;

q 将是单个数组节点或数组节点序列,具体取决于您是否使用 SingleOrDefault()

【讨论】:

这也太好了!我最终选择了这个:XNode node = xmlElements.Elements("dict").Elements("key").Where(k => k.Value == "jobSteps").FirstOrDefault();【参考方案4】:
var q = (from key in xml.Descendants("key")
            where key.Value == "jobSteps"
            from array in xml.Descendants("array")
            select key.NodesAfterSelf() // In all nodes after <key>jobSteps</key>
                    .OfType<XElement>() // which are elements
                    .Where(element => element.Name == "array") // and name is array,
                    .First() // select first of them
        ).First(); // and select first of whatever is found

注意:如果没有找到结果,上面的代码可能会在调用First() 时抛出InvalidOperationException

【讨论】:

以上是关于LINQ to XML:如何选择下一个元素的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 LINQ 选择特定元素名称?

LINQ to XML:如何在 C# 中获取元素值?

LINQ to XML - 如何修复根元素中的默认命名空间

如何/我可以使用 linq to xml 以合理的内存消耗查询巨大的 xml 文件?

如何使用 LINQ 在 XML 中按名称获取元素

如何编写这个 Linq-to-SQL 选择查询