使用LINQ提取XML时文件名、cName、cValue获取错误求助
问题背景
项目需要读取构建区域预期结果的XML文件,与构建日志对比判断构建是否通过。但用LINQ提取数据时出现异常:输出的文件名重复,cName与预期不符。
错误输出示例
FileName: Test.dll, cName: BuildStatus, cValue: Success
FileName: Test.dll, cName: BuildStatus, cValue: Success
FileName: Test.dll, cName: BuildStatus, cValue: Success
期望输出示例
FileName: Test.dll, cName: Version, cValue: 1.0.0.0
FileName: Utils.dll, cName: BuildStatus, cValue: Success
FileName: Core.exe, cName: Checksum, cValue: ABC123
相关代码与XML结构
C# LINQ代码(原错误版本)
var doc = XDocument.Load("buildResult.xml"); var results = from file in doc.Descendants("File") from prop in doc.Descendants("Property") select new { FileName = file.Attribute("name").Value, cName = prop.Attribute("name").Value, cValue = prop.Attribute("value").Value }; foreach(var item in results) { Console.WriteLine($"FileName: {item.FileName}, cName: {item.cName}, cValue: {item.cValue}"); }
XML结构示例
<BuildResults> <File name="Test.dll"> <Property name="Version" value="1.0.0.0" /> <Property name="BuildStatus" value="Success" /> </File> <File name="Utils.dll"> <Property name="BuildStatus" value="Success" /> </File> <File name="Core.exe"> <Property name="Checksum" value="ABC123" /> </File> </BuildResults>
问题原因与修复
问题根源
原代码中from prop in doc.Descendants("Property")是遍历整个XML文档的所有Property节点,而非当前File节点的子节点。这会导致每个File和所有Property做笛卡尔积,最终出现文件名重复、cName不匹配的问题。
修复后的代码
将doc.Descendants("Property")改为file.Descendants("Property"),确保只遍历当前File节点下的属性:
var doc = XDocument.Load("buildResult.xml"); var results = from file in doc.Descendants("File") from prop in file.Descendants("Property") select new { FileName = file.Attribute("name").Value, cName = prop.Attribute("name").Value, cValue = prop.Attribute("value").Value }; foreach(var item in results) { Console.WriteLine($"FileName: {item.FileName}, cName: {item.cName}, cValue: {item.cValue}"); }
优化建议
如果Property是File的直接子节点,用file.Elements("Property")替代file.Descendants("Property"),性能更优——Elements仅查找直接子节点,Descendants会遍历所有后代节点。
内容的提问来源于stack exchange,提问作者Michele

