LINQ to XML 如何选择不同层级的多个元素
解决LINQ to XML从不同层级选择多元素的问题
看起来你已经找对了大致方向,只是在元素访问的细节上出了点小问题。咱们一步步修正你的查询,实现从不同层级返回多个值的需求。
问题分析
你的原查询有几个关键问题:
- 集合不能直接访问
.Value:prop.Elements(ns + "Name")返回的是元素集合,哪怕实际只有一个<Name>元素,也不能直接用.Value,得用Element()获取单个元素后再取值。 - 子元素匹配不够精准:
from templateName in getValue.Elements()会匹配<GetValue>下的所有子元素,最好明确指定<TemplateName>元素,避免意外匹配其他节点。 - 属性访问不安全:
pset.Attribute("referenceId").Value如果遇到属性不存在的情况会抛出空引用异常,直接强转成string更安全:(string)pset.Attribute("referenceId")。
方案1:使用匿名类型(快速实现)
直接在select里创建匿名对象,包含你需要的两个值:
// 替换成你的XML命名空间 XNamespace ns = "你的XML命名空间"; string set = "Common"; // 你要匹配的referenceId IEnumerable<object> propertyData = from psetdefs in xElement.Elements(ns + "PropertySetDefinitions") from pset in psetdefs.Elements(ns + "PropertySet") where (string)pset.Attribute("referenceId") == set from props in pset.Elements(ns + "Properties") from prop in props.Elements(ns + "Property") from propValue in prop.Elements(ns + "PropertyValue") from valCon in propValue.Elements(ns + "ValueConversion").DefaultIfEmpty(propValue) from getValue in valCon.Elements(ns + "GetValue") from templateName in getValue.Elements(ns + "TemplateName") select new { PropertyName = (string)prop.Element(ns + "Name"), TemplateValue = templateName.Value };
遍历propertyData时,你可以直接访问每个对象的PropertyName和TemplateValue属性。
方案2:使用自定义类(适合复杂场景)
如果后续需要在多个地方复用这个结果,定义自定义类会更清晰:
// 先定义承载数据的类 public class PropertyTemplatePair { public string PropertyName { get; set; } public string TemplateValue { get; set; } } // 修改查询返回这个类的实例 IEnumerable<PropertyTemplatePair> propertyData = from psetdefs in xElement.Elements(ns + "PropertySetDefinitions") from pset in psetdefs.Elements(ns + "PropertySet") where (string)pset.Attribute("referenceId") == set from props in pset.Elements(ns + "Properties") from prop in props.Elements(ns + "Property") from propValue in prop.Elements(ns + "PropertyValue") from valCon in propValue.Elements(ns + "ValueConversion").DefaultIfEmpty(propValue) from getValue in valCon.Elements(ns + "GetValue") from templateName in getValue.Elements(ns + "TemplateName") select new PropertyTemplatePair { PropertyName = (string)prop.Element(ns + "Name"), TemplateValue = templateName.Value };
额外的容错处理
如果某些节点可能不存在(比如部分<Property>没有<TemplateName>),可以用DefaultIfEmpty()避免查询中断,同时设置默认值:
from templateName in getValue.Elements(ns + "TemplateName").DefaultIfEmpty() select new { PropertyName = (string)prop.Element(ns + "Name") ?? "Unnamed Property", TemplateValue = templateName?.Value ?? "No Template" };
这样就算节点缺失,查询也能正常返回,不会抛出异常。
内容的提问来源于stack exchange,提问作者Ryan Daley
相关产品推荐
相关产品推荐

