Reputation: 5696
Grettings!
I have some XML that looks like this:
<Root>
<SectionA>
<Item id="111">
<Options>
<Option val="a" cat="zzz">
<Package value="apple" />
<Feature value="avacado" />
</Option>
<Option val="b" cat="yyy">
<Package value="banana" />
<Feature value="blueberry" />
</Option>
</Options>
</Item>
<Item id="222">
<Options>
<Option val="c" cat="xxx">
<Package value="carrot" />
<Feature value="cucumber" />
</Option>
<Option val="d" cat="www">
<Package value="dairy" />
<Feature value="durom" />
</Option>
</Options>
</Item>
</SectionA>
<SectionB>
.
.
.
</SectionB>
</Root>
I'd like to get the PACKAGE and FEATURE values based on the ID attribute of ITEM being "111" and the VAL attribute of OPTION being "a".
I'm not sure where to start. I'm able to select the ITEM node using a where, but I'm not sure how to combine that with a where clause on the OPTION node. Any ideas?
Upvotes: 3
Views: 1089
Reputation: 104721
And here is the VB version (VB really rocks++ in xml stuff):
Module Module1
Sub Main()
Dim xml As XElement = <Root>
<SectionA>
<Item id="111">
<Options>
<Option val="a" cat="zzz">
<Package value="apple"/>
<Feature value="avacado"/>
</Option>
<Option val="b" cat="yyy">
<Package value="banana"/>
<Feature value="blueberry"/>
</Option>
</Options>
</Item>
<Item id="222">
<Options>
<Option val="c" cat="xxx">
<Package value="carrot"/>
<Feature value="cucumber"/>
</Option>
<Option val="d" cat="www">
<Package value="dairy"/>
<Feature value="durom"/>
</Option>
</Options>
</Item>
</SectionA>
<SectionB>
</SectionB>
</Root>
Dim data = From x In xml...<Option> _
Where x.Ancestors("Item").@id = "111" AndAlso x.@val = "a" _
Select Package = x.<Package>.@value, _
Feature = x.<Feature>.@value
For Each item In data
Console.WriteLine("Package: {0}, Feature: {1}", item.Package, item.Feature)
Next
Stop
End Sub
End Module
Upvotes: 0
Reputation: 38346
This works for me.
var doc = XDocument.Parse(s);
var items = from item in doc.Descendants("Item")
where item.Attribute("id").Value == "111"
from option in item.Descendants("Option")
where option.Attribute("val").Value == "a"
let package = option.Element("Package").Attribute("value")
let feature = option.Element("Feature").Attribute("value")
select new { Package = package.Value, Feature = feature.Value };
items.First().Feature; // = "avacado"
items.First().Package; // = "apple"
You can omit the let
parts if you want, they are only to make the anonymous type thinner.
var items = from item in doc.Descendants("Item")
where item.Attribute("id").Value == "111"
from option in item.Descendants("Option")
where option.Attribute("val").Value == "a"
select new
{
Package = option.Element("Package").Attribute("value").Value,
Feature = option.Element("Feature").Attribute("value").Value
};
Actually, I kind of like the second one more.
And the non query Linq style.
var items = doc.Descendants("Item")
.Where(item => item.Attribute("id").Value == "111")
.SelectMany(item => item.Descendants("Option"))
.Where(option => option.Attribute("val").Value == "a")
.Select(option => new
{
Package = option.Element("Package").Attribute("value").Value,
Feature = option.Element("Feature").Attribute("value").Value
});
Upvotes: 7
Reputation: 25099
Here's a bottom-up approach:
var items = xdoc
.Descendants("Option")
.Where(o => (string)o.Attribute("val") == "a" && (int)o.Ancestors("Item").Single().Attribute("id") == 111)
.Select(o => new {
Package = o.Element("Package"),
Feature= o.Element("Feature")
});
Upvotes: 0
Reputation: 123642
alternate implementation using SelectMany
var doc = XDocument.Parse(xml);
var items = from i in doc.Descendants("Item")
from o in i.Descendants("Option")
where i.Attribute("id").Value == "111"
&& o.Attribute("val").Value == "a"
select new {
Package = i.Descendants("Package").Attribute("value").Value,
Feature = i.Descendants("Feature").Attribute("value").Value
};
Upvotes: 4