How to: Find Child Elements Based on Position (XPath-LINQ to XML)
Sometimes you want to find elements based on their position. You might want to find the second element, or you might want to find the third through the fifth element.
The XPath expression is:
Test[position() >= 2 and position() <= 4]
There are two approaches to writing this LINQ to XML query in a lazy way. You can use the Skip<TSource> and Take<TSource> operators, or you can use the Where overload that takes an index. When you use the Where overload, you use a lambda expression that takes two arguments. The following example shows both methods of selecting based on position.
Example
This example finds the second through the fourth Test element. The result is a collection of elements.
This example uses the following XML document: Sample XML File: Test Configuration (LINQ to XML).
XElement testCfg = XElement.Load("TestConfig.xml");
// LINQ to XML query
IEnumerable<XElement> list1 =
testCfg
.Elements("Test")
.Skip(1)
.Take(3);
// LINQ to XML query
IEnumerable<XElement> list2 =
testCfg
.Elements("Test")
.Where((el, idx) => idx >= 1 && idx <= 3);
// XPath expression
IEnumerable<XElement> list3 =
testCfg.XPathSelectElements("Test[position() >= 2 and position() <= 4]");
if (list1.Count() == list2.Count() &&
list1.Count() == list3.Count() &&
list1.Intersect(list2).Count() == list1.Count() &&
list1.Intersect(list3).Count() == list1.Count())
Console.WriteLine("Results are identical");
else
Console.WriteLine("Results differ");
foreach (XElement el in list1)
Console.WriteLine(el);
Dim testCfg As XElement = XElement.Load("TestConfig.xml")
' LINQ to XML query
Dim list1 As IEnumerable(Of XElement) = _
testCfg.Elements("Test").Skip(1).Take(3)
'LINQ to XML query
Dim list2 As IEnumerable(Of XElement) = _
testCfg.Elements("Test"). _
Where(Function(ByVal el, ByVal idx) idx >= 1 And idx <= 3)
' XPath expression
Dim list3 As IEnumerable(Of XElement) = _
testCfg.XPathSelectElements("Test[position() >= 2 and position() <= 4]")
If list1.Count() = list2.Count() And _
list1.Count() = list3.Count() And _
list1.Intersect(list2).Count() = list1.Count() And _
list1.Intersect(list3).Count() = list1.Count() Then
Console.WriteLine("Results are identical")
Else
Console.WriteLine("Results differ")
End If
For Each el As XElement In list1
Console.WriteLine(el)
Next
This example produces the following output:
Results are identical
<Test TestId="0002" TestType="CMD">
<Name>Find succeeding characters</Name>
<CommandLine>Examp2.EXE</CommandLine>
<Input>abc</Input>
<Output>def</Output>
</Test>
<Test TestId="0003" TestType="GUI">
<Name>Convert multiple numbers to strings</Name>
<CommandLine>Examp2.EXE /Verbose</CommandLine>
<Input>123</Input>
<Output>One Two Three</Output>
</Test>
<Test TestId="0004" TestType="GUI">
<Name>Find correlated key</Name>
<CommandLine>Examp3.EXE</CommandLine>
<Input>a1</Input>
<Output>b1</Output>
</Test>