views:

308

answers:

2

With LinqToXml I would like to read out the album list for a given artist from an xml file like

<?xml version="1.0" encoding="utf-8" ?>
<artists>
  <artist name="Beatles">
    <albums>
      <album title="Please Please Me" year="1963"/>
      <album title="With the Beatles" year="1963"/>
      ...
    </albums>
  </artist>
  ...

I tried the following with LinqToXml. However, I would like to avoid instantiating an artist object...

XDocument xartists = XDocument.Load(FilePhysicalPath);
var artists = from xartist in xartists.Descendants("artist")
              where xartist.Attribute("name").Value.Equals(id)
              select new MusicArtist
              {
                  Albums = from xalbum in xartist.Descendants("album")
                           select new MusicAlbum
                           {
                               Title = xalbum.Attribute("title").Value,
                               Year =
                               int.Parse(xalbum.Attribute("year").Value)
                           }
              };
var artist = artists.SingleOrDefault();
if (artist != null)
    return artist.Albums;
else
    return null;


Update: My current 'best' attempt: See the accepted answer.

+2  A: 

Try something like this:

    return (from artist in 
                     (from xartist in xartists.Descendants("artist")
                     where xartist.Attribute("name").Value.Equals("Beatles")
                     select new MusicArtist
                     {
                         Albums = from xalbum in xartist.Descendants("album")
                                  select new MusicAlbum
                                  {
                                      Title = xalbum.Attribute("title").Value,
                                      Year =  int.Parse(xalbum.Attribute("year").Value)
                                  }
                     })
                  where artist != null
                 select artist).FirstOrDefault();
womp
Thanks. The original answer helped me simplify the expression with anonymous types. But the current answer gives me nothing new. And I'm not sure if 'too much' is instantiated in memory. (Not that it matters much in the actual application, but I would like to learn how to minimize memory usage.)
Ole Lynge
+1  A: 

It should be something like:

var result = from artist in xartists.Root.Elements("artist")
             where artist.Attribute("name").Value.Equals(id)
             let albums = artist.Element("albums")
             from album in albums.Elements("album")
             select new MusicAlbum
             {
                 Title = album.Attribute("title").Value,
                 Year = (int) album.Attribute("year")
             };

Note in particular the use of Element/Elements instead of Descendents

Marc Gravell
Thanks for the nice and helpful answer.
Ole Lynge