Don Diego
Don Diego

Reputation: 1498

Select an element who as a last child with property

<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

Answers (1)

Julia Hayward
Julia Hayward

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

Related Questions