views:

99

answers:

5

Here is my XML

<assets>
    <asset>
        <metadata Id="ItemType" Value="Image"/>
        <metadata Id="ItemUri" Value="http://blah.png"/&gt;
    </asset>
    <asset>
        <metadata Id="ItemType" Value="Image"/>
        <metadata Id="ItemUri" Value="http://blah2.png"/&gt;
    </asset>
</assets>

How do I get the 2nd <metadata>'s value containing the URI?

List<Asset> assets = (from asset in xmlDocument.Descendants("asset")
                              select new Asset
                              {
                                  ItemType = asset.Element("metadata").Attribute("Value").Value,
                                  ItemUri = asset.Element("metadata").Attribute("Value").Value
                              }).ToList<Asset>();

Currently my code just returns the same value from the first <metadata> of course.

A: 

Seems that .Element(..) gets the first element with matching name if multiple elements are present. You can edit the linq query to something like

var assets = (from asset in doc.Descendants("asset")
                 let metadata = asset.Descendants("metadata").ToArray()
                 let type = metadata[0].Attribute("Value").Value
                 let uri = metadata[1].Attribute("Value").Value
                 select new Asset { ItemType = type, ItemUri = uri }).ToList();
Zebi
A: 
var assets = (from asset in xmlDocument.Descendants("asset")
              select new Asset
              {
                  ItemType = (string)asset.Element("metadata").Attribute("Value"),
                  ItemUri = (string)asset.Elements("metadata").ElementAt(1).Attribute("Value")
              }).ToList();
lasseespeholt
A: 

See How to: Find Sibling Nodes

bnieland
+2  A: 

This is what I ended up doing. The answers above where good but if the <metadata>s are not in order then I'll get the wrong data. This way I do a query and get the correct one no matter the order.

List<Asset> assets = (from asset in xmlDocument.Descendants("asset")
                              select new Asset
                              {
                                  ItemType = asset.Elements().Single(x => x.Attribute("Id").Value == "ItemType").Attribute("Value").Value,
                                  ItemUri = asset.Elements().Single(x => x.Attribute("Id").Value == "ItemUri").Attribute("Value").Value,    
                              }).ToList<Asset>();
Aaron Salazar
I'd up vote, but I'm out of votes for the day
Matt Ellen
I'll do it for you ;-) +1 for the order-independent solution. It is quite sad that so much code has to be written for such a small thing :-/ but I don't know how it could be cleaner/smaller ;-).
lasseespeholt
A: 

This code will give you an IEnumerable of some anonymous type, but you already know how to turn it into the right type.

var assets = from asset in xd.Descendants("asset")
             from metaType in asset.Descendants("metadata")
             from metaUri in asset.Descendants("metadata")
             where metaType.Attribute("Id").Value == "ItemType"
             && metaUri.Attribute("Id").Value == "ItemUri"
             select new
             {
                 ItemType = metaType.Attribute("Value").Value,
                 ItemUri = metaUri.Attribute("Value").Value
             };
Matt Ellen