Linq to 根据嵌套子项的属性选择父项

Linq to Select a Parent based on Attribute of a Nested Child

提问人:Ryan Daley 提问时间:7/1/2022 最后编辑:MarkusRyan Daley 更新时间:7/1/2022 访问量:293

问:

我正在使用 System.Xml.Linq 以便从此 XML 文件中获取我需要的信息。我需要最终得到一个在子元素中具有正确 entityType 的 referenceId 列表。

这是我正在使用的 XML 文件的示例。

<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>

这是我能想到的最好的 Linq 查询,但它不返回任何内容。一旦我尝试查询属性,似乎没有任何效果

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

我认为这可能与访问属性的值有关。没有 Attributes(“entityType”) 的属性。值 此外,如果我尝试简单地返回所有“entityType”属性,它将返回属性的名称和值:

enter image description here

我认为这个查询很复杂,有几个原因。

  1. XML 树的深度(嵌套子项)。
  2. 需要使用属性值。

如果有人知道如何进行这种类型的 Linq 查询,请告诉我。

C# LINQ-to-XML

评论

0赞 Charlieface 7/1/2022
.Attributes("entityType").FirstOrDefault().Value == "IfcBeam")

答:

1赞 SynerCoder 7/1/2022 #1
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);

其工作原理如下:

  1. 选择元素PropertySetBindings
  2. 选择子项PropertySetBind
  3. 将子元素筛选为具有元素的子元素,这些元素具有属性,值为“IfcBeam”。RulesIncludeentityType
  4. 从这些元素中,选择“referenceId”属性PropertySetBind
  5. 检查 null(属性存在)
  6. 选择属性的值(这样就没有“referenceId=value”,只有值)

评论

0赞 Ryan Daley 7/1/2022
谢谢!我从你的花哨裤子查询中学到了很多东西!
0赞 SynerCoder 7/1/2022
如果这对您有帮助,请考虑投赞成票,或将此答案标记为已接受。这是让社区看到这是一个很好的答案的简单方法。
0赞 Ryan Daley 7/1/2022 #2

好的,我找到了一个可行的解决方案! 我只能使用此查询表示法(我认为它被调用)而不是 Lambda 表示法来让它工作。这允许访问属性的值。

            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;

如果您对此问题有更优雅的解决方案,请告诉我。

0赞 Michalor 7/1/2022 #3

找到这个解决方案:

 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);