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

14
我有一个来自 iPhone 应用的 plist 文件。它看起来像下面这样:

I have a plist file from an iPhone app. It looks like this below:

<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的元素后面的下一个项目。


为什么不直接通过名称获取<array>节点呢? - Metro Smurf
4个回答

18

我不完全清楚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,这正是我想要的。 - Matt Hudson
谢谢 - 在你发帖之前不久,我意识到我的原始答案不够充分了。+1 :) - Adam Rackis
Jon,为了增进我的理解,当你说CW(element.NextNode)时,它是否会显示节点的XML值?我知道XElement:XNode,我只是想知道使用节点相对于元素有什么用处。 - Adam Rackis
@Adam:它显示节点的ToString方法返回的内容。对于文本节点,它是文本...... 对于元素节点,它是包括子元素在内的完整元素。通常情况下,使用XElement比XNode更容易处理,是的。 - Jon Skeet

5

编辑

我相信这将帮助您获取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 
 }

2
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(); - Matt Hudson

1
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异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接