Home > Enterprise >  Linq to Select a Parent based on Attribute of a Nested Child
Linq to Select a Parent based on Attribute of a Nested Child

Time:07-02

I am using System.Xml.Linq in order to get the information I need from this XML file. I need to end up with a List of the referenceId's that have the correct entityType in the child element.

Here is a sample of the XML file I am working with.

<PropertySetBindings>
<PropertySetBind referenceId="assemblies">
  <Rules>
    <Include entityType="IfcElementAssembly" subtypes="true" />
  </Rules>
</PropertySetBind>
<PropertySetBind referenceId="beam_common">
  <Rules>
    <Include entityType="IfcBeam" subtypes="false" />
  </Rules>  
</PropertySetBind>
<PropertySetBind referenceId="column_common">
  <Rules>
    <Include entityType="IfcColumn" subtypes="false" />
  </Rules>  
</PropertySetBind>

This is the best Linq query I can come up with, but it doesn't return anything. Nothing seems to work as soon as I try to query the attributes

 var bindings = xElement.Elements("PropertySetBindings")
   .Elements("PropertySetBind")
   .Where(x => x.Elements("Rules")
   .Elements("Include")                           
   .Attributes("entityType").FirstOrDefault().Equals("IfcBeam"))
   .Select(x => x.Attribute("referenceId"));  

I think this might have to do with accessing the value of the attribute. There is no property for Attributes("entityType").Value Also, if I try to simply return all the "entityType" attributes, it returns the name and value of the attribute:

enter image description here

I think this query is complex for a couple reasons.

  1. Depth of the XML Tree (nested children).
  2. The need to use the attribute values.

Let me know if anyone knows how to do this type of Linq query.

CodePudding user response:

var referenceIds = xElement.Element("PropertySetBindings")
    .Elements("PropertySetBind")
    .Where(x => x.Elements("Rules")
        .Any(r => r.Elements("Include")
            .Any(i => i.Attributes("entityType")
                .Any(a => a.Value == "IfcBeam")
            )
        )
    )
    .Select(x => x.Attribute("referenceId"))
    .Where(x => x != null)
    .Select(x => x.Value);

It works as follows:

  1. select the PropertySetBindings element
  2. select the PropertySetBind children
  3. filter the children to children with Rules elements, that have Include elements that have entityType attributes, that have a value of 'IfcBeam'.
  4. from those PropertySetBind elements, select the 'referenceId' attribute
  5. check for null (attribute exists)
  6. select the value of the attribute (so you dont have the "referenceId=value", just the value)

CodePudding user response:

Okay, I found a working solution! I can only get it to work with using this query notation (I think its called) instead of the Lambda notation. This allows for accessing the value of the attribute.

            var bindings = from binding in xElement.Elements("PropertySetBindings")
                       from bind in binding.Elements("PropertySetBind")
                       from ru in bind.Elements("Rules")
                       from inc in ru.Elements("Include")
                       where (string)inc.Attribute("entityType") == "IfcBeam"
                       select bind.Attribute("referenceId").Value;

Let me know if you have a more elegant solution to this problem.

CodePudding user response:

Found this solution:

 var bindings = xElement.Elements("PropertySetBindings")
    .Elements("PropertySetBind")                       
    .Where(x => x.Elements("Rules").FirstOrDefault()
    .Elements("Include").FirstOrDefault()                         
    .Attributes("entityType").FirstOrDefault().Value.Equals("IfcBeam"))
    .Select(x => x.Attributes("referenceId").FirstOrDefault().Value);  
  • Related