如何从含HasToys=YES属性的XML节点提取所有ToyId到数组?
解决C# LINQ提取XML中所有ToyId的问题
问题场景
需要从带有HasToys="YES"属性的<Bookstore>节点中提取所有<ToyId>的值并存入数组,但现有LINQ查询仅返回首个ToyId,其余值均被遗漏。
原XML代码
<Bookstore Hastoys="YES"> <Authors>7</Authors> <Location>Austin TX</Location> <Employees>15</Employees> <ToyList> <ToyId>124</ToyId> <ToyId>1251</ToyId> </ToyList> <ToyList> <ToyId>255-2</ToyId> <ToyId>6623</ToyID> </ToyList> </Bookstore>
原问题代码
var list = from r in doc.Descendants("Bookstore") .Where(node => (string)node.Attribute("HasToys") == "YES") select new { ToyId = r.Element("ToyList")?.Element("ToyId")?.Value, };
问题原因
原代码中r.Element("ToyList")只会获取当前<Bookstore>下的第一个<ToyList>节点,后续的<ToyList>会被忽略;同时Element("ToyId")又只取该<ToyList>下的第一个<ToyId>,最终仅能拿到单个值。
解决方案
方案1:使用SelectMany扁平化所有ToyId
通过SelectMany将每个符合条件的<Bookstore>下的所有<ToyId>节点扁平化,统一提取值后转为数组:
var toyIds = doc.Descendants("Bookstore") .Where(node => (string)node.Attribute("HasToys") == "YES") .SelectMany(bookstore => bookstore.Descendants("ToyId")) .Select(toyId => toyId.Value) .ToArray();
方案2:LINQ查询语法嵌套遍历
用嵌套的LINQ查询语法,依次遍历符合条件的<Bookstore>、其下所有<ToyList>、每个<ToyList>下的<ToyId>:
var toyIds = (from bookstore in doc.Descendants("Bookstore") where (string)bookstore.Attribute("HasToys") == "YES" from toyList in bookstore.Elements("ToyList") from toyId in toyList.Elements("ToyId") select toyId.Value).ToArray();
注意事项
原XML中最后一个<ToyId>标签写成了<ToyID>(大写D),XML标签是大小写敏感的,因此这个值会被上述查询忽略。如果需要包含该值,可修改XML标签为统一的<ToyId>,或者调整查询以忽略标签名大小写:
var toyIds = doc.Descendants("Bookstore") .Where(node => (string)node.Attribute("HasToys") == "YES") .SelectMany(bookstore => bookstore.Descendants() .Where(n => n.Name.Equals("ToyId", StringComparison.OrdinalIgnoreCase))) .Select(toyId => toyId.Value) .ToArray();
内容的提问来源于stack exchange,提问作者That1Flipipino
相关产品推荐
相关产品推荐

