LINQ to XML按嵌套子元素属性筛选父节点取referenceId
LINQ to XML 多层节点属性筛选正确写法
原代码失效原因
你的查询返回空是两个核心错误导致的:
- 节点层级匹配错误:如果
xElement本身就是<PropertySetBindings>根节点,再调用.Elements("PropertySetBindings")会查找当前节点下名为PropertySetBindings的子节点,自然匹配不到任何内容。 - 属性值比对逻辑错误:
Attributes("entityType").FirstOrDefault()返回的是XAttribute类型对象,不是属性值字符串,直接和字符串"IfcBeam"做Equals比对永远返回false,必须取属性的Value属性才能拿到实际的属性值,同时要做空判断避免空引用异常。
可直接运行的实现代码
如果你的XML结构固定,推荐严格按层级查询,性能更好:
// 前提:xElement 为 <PropertySetBindings> 根节点 var referenceIdList = xElement .Elements("PropertySetBind") .Where(bindNode => bindNode .Elements("Rules") .Elements("Include") // 显式转string可避免属性不存在时抛出空引用异常 .Any(includeNode => (string)includeNode.Attribute("entityType") == "IfcBeam")) .Select(bindNode => (string)bindNode.Attribute("referenceId")) .ToList();
如果XML层级可能变动,可以用Descendants跳过中间层级直接查找目标节点,写法更灵活:
var referenceIdList = xElement .Descendants("Include") .Where(includeNode => (string)includeNode.Attribute("entityType") == "IfcBeam") // 向上两级找到PropertySetBind节点取referenceId .Select(includeNode => (string)includeNode.Parent?.Parent?.Attribute("referenceId")) .Where(id => !string.IsNullOrEmpty(id)) .ToList();
以上代码运行后,针对你给出的示例XML,会正确返回["beam_common"]的结果。
编写这类查询的注意点
- 优先使用
(string)XAttribute/(int)XAttribute这类显式转换的方式取值,比直接调用.Value属性更安全,属性不存在时会返回null,不会触发空引用异常。 - 判断子节点是否存在符合条件的项时,用
Any()方法做判断,不要直接取FirstOrDefault()后直接访问属性,避免序列为空时报错。 - 如果XML带默认命名空间,需要先声明
XNamespace,用命名空间拼接本地名作为参数传入Elements/Attribute方法,否则会匹配不到节点。
内容的提问来源于stack exchange,提问作者Ryan Daley
相关产品推荐
相关产品推荐

