C # Linq XML Query where multiple elements with the same name exist

Linq newbie here. There was a search and could not find the exact question; tried to work from other answers that were similar but still couldn't get it.

Cannot return all instances of the specified item name. I can return one item, but not all.

Here is the XML:

<?xml version="1.0"?>
<printerlist>
  <list type="aff">
    <printserver>print-server1</printserver>
    <printserver>print-server2</printserver>
    <printserver>print-server3</printserver>
  </list>
  <list type="lff">
    <printserver>print-sever4</printserver>
    <additionalprinters>
      <printer>
        <fullname>\\serverb\bbb</fullname>
      </printer>
      <printer>
        <fullname>\\serverc\aaa</fullname>
      </printer>
    </additionalprinters>
  </list>
</printerlist>

      

And here is the code to try and get the list:

var query = from c in xml.Root.Descendants("list")
    where (string)c.Attribute("type") == "aff"
    select c.Element("printserver");

foreach (string name in query)
{
    Console.WriteLine("Server Name: {0}", name);
}

      

This only creates the first printserver server element: print-server1 How can I get foreach to list all 3 servers that are in the contact list?

thank

+3


source to share


2 answers


You need to use Elements("printserver")

instead Element("printserver")

like this:

var query = (from c in doc.Root.Descendants("list").Elements("printserver")
             where (string)c.Parent.Attribute("type") == "aff"
             select c);

      

or using SelectMany()

like this:



var query = (from c in doc.Root.Descendants("list")
             where (string)c.Attribute("type") == "aff"
             select c).SelectMany(c => c.Elements("printserver"));

      

or if you are sure that only one item matches the sentence where

, you can use First()

like this:

var query = (from c in doc.Root.Descendants("list")
             where (string)c.Attribute("type") == "aff"
             select c).First().Elements("printserver"));

      

+2


source


How about something like this:

List<XElement> elements = doc.Root.Descendants("printserver")
                                 .Where(e => e.Parent.Name == "list" && e.Parent.Attribute("type").Value == "aff")
                                 .ToList();

      

Then if you want to loop through the elements:

foreach (XElement e in elements)
{
    Console.WriteLine("Server Name : {0}", e.Value);
}

      



If you just want string values ​​for each print server, use .Select at the end:

List<string> elements = doc.Root.Descendants("printserver")
                                .Where(e => e.Parent.Name == "list" && e.Parent.Attribute("type").Value == "aff")
                                .Select(p => p.Value)
                                .ToList();

      

The above solution allows you to use your current foreach loop.

+1


source







All Articles