Chris
Chris

Reputation: 123

return all xml items with same name in linq

how can I query an xml file where I have multiple items with the same name, so that I can get all items back. Currently I only get the first result back. I managed to get it to work with the following code, but this returns all items where the specific search criteria is met. What I want as output is to get two results back where the location is Dublin for example. The question is how can I achieve this with linq to xml

Cheers Chris,

Here is the code

string location = "Oslo";    
var training = (from item in doc.Descendants("item")
                         where item.Value.Contains(location)

                      select  new
                         {
                             event = item.Element("event").Value,
                             event_location = item.Element("location").Value
                         }).ToList();

The xml file looks like this

<training>
   <item>
      <event>C# Training</event>
        <location>Prague</location>
        <location>Oslo</location>
        <location>Amsterdam</location>
        <location>Athens</location>
        <location>Dublin</location>
        <location>Helsinki</location>
   </item>       
   <item>
        <event>LINQ Training</event>
        <location>Bucharest</location>
        <location>Oslo</location>
        <location>Amsterdam</location>
        <location>Helsinki</location>
        <location>Brussels</location>
        <location>Dublin</location>
   </item>            
</training> 

Upvotes: 4

Views: 2833

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1500514

You're using item.Element("location") which returns the first location element under the item. That's not necessarily the location you were looking for!

I suspect you actually want something more like:

string location = "Oslo";
var training = from loc in doc.Descendants("location")
               where loc.Value == location
               select new
               {
                   event = loc.Parent.Element("event").Value,
                   event_location = loc.Value
               };

But then again, what value does event_location then provide, given that it's always going to be the location you've passed into the query?

If this isn't what you want, please give more details - your question is slightly hard to understand at the moment. Details of what your current code gives and what you want it to give would be helpful - as well as what you mean by "name" (in that it looks like you actually mean "value").

EDIT: Okay, so it sounds like you want:

string location = "Oslo";
var training = from loc in doc.Descendants("location")
               where loc.Value == location
               select new
               {
                   event = loc.Parent.Element("event").Value,
                   event_locations = loc.Parent.Elements("location")
                                               .Select(e => e.Value)
               };

event_locations will now be a sequence of strings. You can get the output you want with:

for (var entry in training)
{
     Console.WriteLine("Event: {0}; Locations: {1}",
                       entry.event,
                       string.Join(", ", entry.event_locations.ToArray());
}

Give that a try and see if it's what you want...

Upvotes: 5

Andy
Andy

Reputation: 30418

This might not be the most efficient way of doing it, but this query works:

var training = (from item in root.Descendants("item")
                where item.Value.Contains(location)
                select new
                {
                    name = item.Element("event").Value,
                    location = (from node in item.Descendants("location")
                               where node.Value.Equals(location)
                               select node.Value).FirstOrDefault(),
                }).ToList();

(Note that the code wouldn't compile if the property name was event, so I changed it to name.)

I believe the problem with your code was that the location node retrieved when creating the anonymous type didn't search for the node with the desired value.

Upvotes: 0

Related Questions