如何在XML LINQ查询中嵌入If语句处理异构属性节点
问题原因
你原来的写法无法运行的核心原因有三点:
- LINQ查询表达式是连续的完整语法结构,不能在多个from/where子句中间直接插入顶层的if-else控制流块,把查询拆成几段不完整的片段,编译器无法识别这种语法。
- 判断条件里的节点名存在拼写笔误:
ValueConverstion是错误写法,正确节点名是ValueConversion,就算语法写对,笔误也会导致分支判断失效。 - 初始查询逻辑只覆盖了
TemplateName节点,没有处理Uda类型属性对应的UdaName节点,会漏取数据。
实现方案
不需要在查询中嵌入硬分支,直接通过Concat方法把两种路径的节点合并为统一序列即可,逻辑完全兼容两类Property结构:
var propertyNames = from psetdefs in xElement.Elements(ns + "PropertySetDefinitions") from pset in psetdefs.Elements(ns + "PropertySet") where (string)pset.Attribute("referenceId")?.Value == PsetBinding from props in pset.Elements(ns + "Properties") from prop in props.Elements(ns + "Property") from propValue in prop.Elements(ns + "PropertyValue") // 合并两种层级的GetValue节点:直接子级、ValueConversion子级下的节点 from getValue in propValue.Elements(ns + "GetValue") .Concat(propValue.Elements(ns + "ValueConversion").Elements(ns + "GetValue")) // 同时覆盖两类名称节点:TemplateName、UdaName from nameNode in getValue.Elements(ns + "TemplateName") .Concat(getValue.Elements(ns + "UdaName")) select nameNode.Value;
逻辑说明
- 对每个遍历到的
PropertyValue节点,同时收集两个路径下的GetValue节点:直接挂在PropertyValue下的(对应Template类型属性)、挂在ValueConversion子节点下的(对应Uda类型属性),合并为同一个序列后后续逻辑完全共用,不需要写if判断。如果某条路径不存在对应节点,Elements()方法会返回空序列,不会影响最终结果。 - 对每个
GetValue节点,同时提取TemplateName和UdaName的取值,覆盖两类属性的名称存储位置,不会遗漏数据。 - 给属性访问增加了
?.空条件运算符,避免个别节点缺少referenceId属性时抛出空引用异常。
简化写法(结构固定时可用)
如果你的XML结构固定,TemplateName和UdaName只会出现在Property节点的下属层级,不会在其他位置出现同名节点,可以直接用Descendants方法跨层级找目标节点,不需要手动写每一层的遍历路径:
var propertyNames = from psetdefs in xElement.Elements(ns + "PropertySetDefinitions") from pset in psetdefs.Elements(ns + "PropertySet") where (string)pset.Attribute("referenceId")?.Value == PsetBinding from nameNode in pset.Descendants(ns + "TemplateName") .Concat(pset.Descendants(ns + "UdaName")) select nameNode.Value;
内容的提问来源于stack exchange,提问作者Ryan Daley
相关产品推荐
相关产品推荐

