通过使用 LINQ 指定祖先节点从节点获取所有属性值
Posted
技术标签:
【中文标题】通过使用 LINQ 指定祖先节点从节点获取所有属性值【英文标题】:Getting all attribute values from node by specifying the ancestor node using LINQ 【发布时间】:2020-12-02 19:42:42 【问题描述】:假设我有以下 xml 文件:
<ModuleSets>
<ServiceModuleSet Name="serverModules">
<Modules>
<ServiceModule Name="ServerModule1"/>
<ServiceModule Name="ServerModule2"/>
</Modules>
</ServiceModuleSet>
<ServiceModuleSet Name="testBenchModules">
<Modules>
<ServiceModule Name="testBenchModule1"/>
<ServiceModule Name="testBenchModule2"/>
</Modules>
</ServiceModuleSet>
<ServiceModuleSet Name="hostComputerModules">
<Modules>
</Modules>
</ServiceModuleSet>
</ModuleSets>
我想从ServiceModule
节点获取所有属性,方法是在ServiceModuleSet
节点中搜索,其中属性名称等于"serverModules"
。
我是 LINQ 新手并尝试了以下代码:
IEnumerable<string> allServerModules = from item in xmlDocument.Descendants("ServiceModuleSet")
where item.Descendants("ServiceModuleSet").Any(attribute => attribute.Value == "serverModules")
select (string)item.Attribute("Name");
foreach (var serverModule in allServerModules)
Console.WriteLine(serverModule);
很遗憾,我没有将任何结果打印到控制台。使用 LINQ 解决它的正确方法是什么?
【问题讨论】:
docs.microsoft.com/en-us/dotnet/api/… 【参考方案1】:这是我的解决方案建议:
var parsedXml = XDocument.Load("sample.xml");
var serverModules = parsedXml.Descendants("ServiceModuleSet")
.FirstOrDefault(set => set.Attribute("Name")?.Value == "serverModules");
var moduleNames = serverModules?.Descendants("ServiceModule")
.Select(module => module.Attribute("Name")?.Value)
.Where(value => !string.IsNullOrEmpty(value));
if (moduleNames == null) return;
foreach (var moduleName in moduleNames)
Console.WriteLine(moduleName);
-
首先我尝试检索
ServiceModuleSet
,它的Name
属性等于"serverModules"
1.1 如果没有任何后代(满足过滤条件),那么我们不想失败,这就是为什么我使用FirstOrDefault
而不是First
1.2 Name
属性也应用了相同的容错逻辑,这就是我使用空条件运算符 (Attribute("Name")?.
) 的原因
如果我找到了所需的节点,那么我可以寻找它的子节点来询问它们的Name
属性
2.1 再次使用空条件运算符 (serverModules?.Descendants
) 使我们的代码更加健壮
2.2 ServiceModule
节点可能有也可能没有Name
属性,这就是为什么我结合使用空条件运算符(.Attribute("Name")?.
)和空字符串过滤(!string.IsNullOrEmpty
)。
如果我成功并检索了一些数据,那么我会打印它们,否则我会提前退出
【讨论】:
感谢您的解决方案和详细解释!就像我说的那样,我是这个话题的新手,昨天花了几个小时尝试和沮丧,但这正是我正在寻找的。我想我的错误是试图在一个 LINQ 语句中完成它,而不是在两个查询中拆分它。【参考方案2】:我喜欢用字典:
XDocument doc = XDocument.Load(FILENAME);
Dictionary<string, List<string>> dict = doc.Descendants("ServiceModuleSet")
.GroupBy(x => (string)x.Attribute("Name"), y => y)
.ToDictionary(x => x.Key, y => y.Descendants("ServiceModule").Select(z => (string)z.Attribute("Name")).ToList());
【讨论】:
以上是关于通过使用 LINQ 指定祖先节点从节点获取所有属性值的主要内容,如果未能解决你的问题,请参考以下文章