views:

300

answers:

4

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?

+4  A: 

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                     
         };
Orion Edwards
I get the following when trying to get the values for Package and Feature:"does not contain a definition for 'Attribute'".
Bullines
A: 

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") 
            });
Slace
+7  A: 

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
               });
Samuel
+1 because your pipeline seems the most efficient
bendewey
A: 

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
Shimmy