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>
I need to get the array after jobSteps.
I have this so far:
XDocument xml = XDocument.Load(rri.Response);
var q = from elements in xml.Descendants("plist").Descendants("dict")
where elements.Value == "jobSteps"
select elements;
But I need to get the next item after the element that has jobSteps in it.
It's not entirely clear to me whether Adam's solution is what you want, but if not, you might want to look at the NextNode property:
Gets the next sibling node of this node.
For instance, this prints the array element:
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);
}
}
}
Note that it's skipping the whitespace between elements - but if there were any text between that and the array, it wouldn't work - so you'd want:
Console.WriteLine(element.NodesAfterSelf().OfType<XElement>().First());
EDIT
I believe this will get you the element after the jobSteps node:
XElement elementAfterJobsteps = xml.Descendants("plist").FirstOrDefault().Descendants("jobSteps").FirstOrDefault().ElementsAfterSelf().FirstOrDefault();
END EDIT
foreach (XElement El in xml.Descendants("plist")) {
var localResults =
from elements in El.Descendants("dict")
where elements.Value == "jobSteps"
select elements;
//process localResults
}
Or, even simpler, try method syntax
foreach (XElement El in xml.Descendants("plist")) {
var localResults = El.Descendants("dict").Where(dict => dict.Value == "jobSteps");
//process localResults
}
var q = xml
.Descendants("plist")
.Descendants("dict")
.Where(item => item.Value == "jobSteps")
.Select(item => item.NextNode)
.SingleOrDefault() // add this if you expect single match
;
The q
will be either a single array node or a sequence of array nodes depending whether you use SingleOrDefault()
.
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
NOTE: Above code may throw InvalidOperationException
while calling First()
if no result is found.