webdad3
webdad3

Reputation: 9090

linq to xml get all child nodes

I'm trying to query a web.Config file that contains WCF entries.

In the <service> node there is a name attribute that I am trying to match off of. So far my code has worked when doing the matching, but my issue is that it only returns 1 of the <endpoint> nodes.

For example I could have this snippet of xml:

<service name="a">
<endpoint>1</endpoint>
<endpoint>2</endpoint>
<endpoint>3</endpoint>
</service>
<service name="b">
<endpoint>1</endpoint>
<endpoint>2</endpoint>
</service>

Everytime I get a match I want it to display all the <endpoint> child nodes for that match.

This is the code I have so far:

        IEnumerable<XElement> xmlURL =
            from el in xmlFile.Root.Descendants("service")
            where (string)el.Attribute("name") == serviceString
            select el.Element("endpoint");

        Console.WriteLine("Start: " + serviceString);
        foreach (XElement el in xmlURL)
        {
            Console.WriteLine(el);
        }
        Console.WriteLine("End: " + serviceString + "\n\n");

Currently when it does the match only 1 endpoint is shown.

Upvotes: 2

Views: 19810

Answers (1)

CodingGorilla
CodingGorilla

Reputation: 19872

I think you want this:

    IEnumerable<XElement> xmlURL =
        from el in xmlFile.Root.Descendants("service")
        where (string)el.Attribute("name") == serviceString
        select el.Descendants("endpoint");

    Console.WriteLine("Start: " + serviceString);
    foreach (XElement el in xmlURL)
    {
        Console.WriteLine(el);
    }
    Console.WriteLine("End: " + serviceString + "\n\n");

Notice I'm selecting el.Descendants() rather than Element() which will only ever return the first match (http://msdn.microsoft.com/en-us/library/system.xml.linq.xcontainer.element.aspx).

** UPDATE **

I think this is what you want, because you're only conerned with one specific match.

IEnumerable<XElement> xmlURL = 
    (from el in doc.Root.Descendants("service")
    where el.Attribute("name").Value == serviceString
    select el).First().Descendants();

So the result of the LINQ query is, as the compiler tells you, an IEnumerable of IEnumerables, so I take the First() result of which gives me now an IEnumerable<XElement>, and then we call Descendants() on that, which gives you an IEnumerable of the endpoint XElement's.

Also note here that I used the Value property of the XAttribute, you can't simply cast the XAttribute to a string, you have to use that Value property. I didn't catch that in my initial copy/paste answer.

** UPDATE 2 **

The above query can is probably a little easier to understand like this:

doc.Root.Descendants("service")
   .Where(x => x.Attribute("name").Value == serviceString)
   .First()
   .Descendants();

** UPDATE 3 **

There is also the potential for a NRE on the attribute matching, so again this is probably an even better verison. =)

doc.Root.Descendants("service")
   .Where(x => x.Attribute("name") != null && x.Attribute("name").Value == serviceString)
   .First()
   .Descendants();

Upvotes: 7

Related Questions