tags:

views:

93

answers:

1

I'm trying to write a Linq2XML query to query the following XML. I need it to pull back all photos for a given GalleryID.

<Albums>
<Album GalleryId="1" Cover="AlbumCover1.jpg" Title="Album 1">
    <Photos>
        <Photo Title="Image1" URL="img1.jpg" DateAdded="01/01/2010 09:20"/>
        <Photo Title="Image2" URL="img2.jpg" DateAdded="01/01/2010 09:20"/>
        <Photo Title="Image3" URL="img3.jpg" DateAdded="01/01/2010 09:20"/>
    </Photos>
</Album>
<Album GalleryId="2" Cover="AlbumCover1.jpg" Title="Album 2">
    <Photos>
        <Photo Title="Image1" URL="img1.jpg" DateAdded="01/01/2010 09:20"/>
        <Photo Title="Image2" URL="img2.jpg" DateAdded="01/01/2010 09:20"/>

    </Photos>
</Album>
</Albums>

The best I've come up with is

 XDocument xmlDoc = XDocument.Load(GalleryFilePath);
                 var x = from c in xmlDoc.Descendants("Album")
                    where int.Parse(c.Attribute("GalleryId").Value) == GalleryId
                    orderby c.Attribute("Title").Value descending
                    select new
                    {
                        Title = c.Element("Photos").Element("Photo").Attribute("Title").Value,
                        URL = c.Element("Photos").Element("Photo").Attribute("URL").Value,
                        DateAdded = c.Element("Photos").Element("Photo").Attribute("DateAdded").Value
                    };

This returns nothing, I'm guessing this is because I'm telling it to query the Album element then trying to loop through the photo elements. Any tips as to how this should be done?

Thanks

Edit : Code updated to reflect answers

+3  A: 

It's a common mistake to confuse the Attribute object with a value. You should use Attribute("x").Value to retrieve it's value.

Try this corrected code:

XDocument xmlDoc = XDocument.Load(GalleryFilePath);
var x = from c in xmlDoc.Descendants("Photo")
        where c.Parent.Parent.Attribute("GalleryId").Value.Equals(GalleryId)
        orderby c.Parent.Parent.Attribute("Title").Value descending
        select new
        {
            Title = c.Attribute("Title").Value,
            URL = c.Attribute("URL").Value,
            DateAdded = c.Attribute("DateAdded").Value
        };

[Update] To retrieve a list of photo's, I've set the from to the photo elements, and the where to the album, which is 2 levels up in the provided sample XML.

Prutswonder
Ok thanks, I've updated to code to use the Value of the Attributes. However the query is now throwing a null reference exception when I call ToList or Count on it.
Gavin Draper
@Gavin in your real data, do all `Album` nodes have both the attributes referred to? Do all `Photo` nodes have all three attributes referred to? If not, `Attribute(name)` will be null which will exception when you invoke `.Value`
AakashM
In that case, use Jon Skeet's extension method: http://stackoverflow.com/questions/792919/how-do-you-guard-for-null-reference-exceptions-in-linq-to-xml/792945#792945
Prutswonder
Yes they all have the same attributes and all attributes have values
Gavin Draper
Ok I fixed the null exception my select was wrong, as the Photo Element is inside a Photos Element. Changing it to c.Element("Photo") Fixed the problem. However I only ever get the first photo returned when I do .ToList(). I think the actual query is wrong somewhere
Gavin Draper
You're right. Let me rewrite it.
Prutswonder
Brilliant thanks!
Gavin Draper