Xtian Macedo
Xtian Macedo

Reputation: 835

Linq to XML: Get all nodes that contain certain children

I have the following XML structure:

<Capabilities>
    <Capability ID="1" Name="Capability # 1">
        <Relations>
            <Relation RelatedTo="2" RelationType="Child"/>
            <Relation RelatedTo="3" RelationType="Child"/>
            <Relation RelatedTo="4" RelationType="Child"/>
            <Relation RelatedTo="5" RelationType="Child"/>
        </Relations>
    </Capability>
    <Capability ID="3" Name="Capability # 3">
        <Relations>
            <Relation RelatedTo="1" RelationType="Dependant" />
        </Relations>
    </Capability>
    <Capability ID="2" Name="Capability # 2">
        <Relations>
            <Relation RelatedTo="6" RelationType="Child" />
            <Relation RelatedTo="5" RelationType="Child" />
        </Relations>
    </Capability>
</Capabilities>

And I need to query the for all Capabilities with a Child relation with RelatedTo attribute of value 5. So far I've tried with the following query but I get a collection of 'null reference exceptions' and I can't figure out how to do it.

   var result = root.Elements("Capability")
                 .Where(c => c.Elements("Relations")
                            .Where(r => r.Attribute("RelatedTo").Value == "5"
                                && r.Attribute("").Value == Enum.GetName(typeof(RelationTypes), RelationTypes.Children)).Any());

Any clues on what I'm doing wrong or what's the correct way to query it?

Upvotes: 2

Views: 2386

Answers (2)

L.B
L.B

Reputation: 116098

var capabilites = root.Descendants("Capability")
            .Where(c => c.Descendants("Relation")
                         .Any(r => (string)r.Attribute("RelatedTo") == "5"))
            .ToList();

Upvotes: 4

Pawel
Pawel

Reputation: 31610

This:

var xDoc = XDocument.Parse(
@"<Capabilities>
<Capability ID=""1"" Name=""Capability # 1""> 
        <Relations> 
            <Relation RelatedTo=""2"" RelationType=""Child""/> 
            <Relation RelatedTo=""3"" RelationType=""Child""/> 
            <Relation RelatedTo=""4"" RelationType=""Child""/> 
            <Relation RelatedTo=""5"" RelationType=""Related""/> 
        </Relations> 
    </Capability> 
    <Capability ID=""3"" Name=""Capability # 3""> 
        <Relations> 
            <Relation RelatedTo=""1"" RelationType=""Dependant"" /> 
        </Relations> 
    </Capability> 
    <Capability ID=""2"" Name=""Capability # 2""> 
        <Relations> 
            <Relation RelatedTo=""6"" RelationType=""Child"" /> 
            <Relation RelatedTo=""5"" RelationType=""Child"" /> 
        </Relations> 
    </Capability> 
</Capabilities>");

var q = xDoc.Descendants("Capability").
            Where(c => c.Descendants("Relation").Where(r => (int)r.Attribute("RelatedTo") == 5).Any());

foreach (var r in q)
{
    Console.WriteLine(r);
}

Results in:

<Capability ID="1" Name="Capability # 1">
  <Relations>
    <Relation RelatedTo="2" RelationType="Child" />
    <Relation RelatedTo="3" RelationType="Child" />
    <Relation RelatedTo="4" RelationType="Child" />
    <Relation RelatedTo="5" RelationType="Related" />
  </Relations>
</Capability>
<Capability ID="2" Name="Capability # 2">
  <Relations>
    <Relation RelatedTo="6" RelationType="Child" />
    <Relation RelatedTo="5" RelationType="Child" />
  </Relations>
</Capability>
Press any key to continue . . .

Which I think what you are after...

Upvotes: 1

Related Questions