Reputation: 1498
<bus>
<port>
<req>
<item>
[...]
</item>
</req>
[...]
<req>
<item>
[...]
</item>
</req>
</port>
[...]
<port>
<req>
<item>
[...]
</item>
</req>
[...]
<req>
<item>
[...]
</item>
</req>
</port>
</bus>
<bus>
[...] (same as before)
</bus>
I have this structure; all the structures repeats themselves. I need to select the last port element of a bus which has a last child with property "mode"=="read".
It can exist a bus which has a last port element with a last child with property different from "read", so I need to choose the right port element.
I tried lots of tries, last one is this, but does not works:
var modbusportSelected = Elements("bus").Elements("port")
.Where( x => x.Elements("req")
.Any(y => y.Attribute("mode").Value.Contains("read")))
.Last();
Any help would be greatly appreciated; also, I'm totally new with LINQ to XML and I cannot find a single webpage where to get the exact meaning of "Any" and if there are other operators, and if so, what they are.
Upvotes: 0
Views: 54
Reputation: 2155
It may be significant that your XML snippet needs a top level element. If you wrap what you have above in an outer tag, then your code appears to work provided you trap null references from any port
elements which don't have a mode
attribute. eg.
using System;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApp1
{
class Program
{
public static string xml = @"<topLevel><bus>
<port isCorrectNode='no'>
<req>
<item>
</item>
</req>
<req mode='read'>
<item>
</item>
</req>
</port>
<port isCorrectNode='yes'>
<req mode='read'>
<item>
</item>
</req>
<req>
<item>
</item>
</req>
</port>
</bus>
<bus>
</bus>
</topLevel>";
static void Main(string[] args)
{
XElement root = XElement.Parse(xml);
var found = root.Elements("bus").Elements("port")
.Where(x => x.Elements("req").Any(y => y.Attribute("mode") != null && y.Attribute("mode").Value.Contains("read")))
.Last();
var isThisTheCorrectNode = found.Attribute("isCorrectNode").Value;
Console.WriteLine(isThisTheCorrectNode);
}
}
}
will write yes
Edit: I've noticed your code looks for the last port
which has any child req
whose mode is 'read'. but your question asked for the last such req
. In that case:
var wanted = root.Elements("bus").Elements("port")
.Where(x => x.Elements("req").Any() && // make sure there is a req element
x.Elements("req").Last().Attribute("mode") != null && // and it has the attribute
x.Elements("req").Last().Attribute("mode").Value.Contains("read")) // and it has the right value
.Last();
Upvotes: 2