C#如何不限层级解析XML获取所有指定名称的PackageReference元素
问题原因
你的csproj文件根节点定义了默认命名空间http://schemas.microsoft.com/developer/msbuild/2003,所有子节点默认归属该命名空间。直接调用Descendants("PackageReference")时,方法会匹配无命名空间的节点,自然找不到结果。
解决方案
两种方案均可实现不限层级查找所有PackageReference节点:
方案1:指定命名空间查找(更严谨)
var text = System.IO.File.ReadAllText(@"C:\MyGit\TestXML3.csproj"); var root = XElement.Parse(text); // 声明XML默认命名空间 XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003"; // 递归查找所有带命名空间的PackageReference节点,不限层级 var packageReferences = root.Descendants(ns + "PackageReference"); foreach (var pkg in packageReferences) { string packageName = pkg.Attribute("Include")?.Value; // 优先取Version属性,没有就取Version子元素的值 string version = pkg.Attribute("Version")?.Value ?? pkg.Element(ns + "Version")?.Value; if (!string.IsNullOrEmpty(packageName) && !string.IsNullOrEmpty(version)) { _packageList.Add(new Package() { App = app, PackageName = packageName, PackageVersion = version, Project = projectName }); // 直接输出可执行:Console.WriteLine($"{packageName};{version}"); } }
方案2:匹配本地名称(兼容性更强,不受命名空间变更影响)
如果不需要严格校验命名空间,可以直接匹配节点的本地名称,不用声明命名空间:
var text = System.IO.File.ReadAllText(@"C:\MyGit\TestXML3.csproj"); var root = XElement.Parse(text); // 递归查找所有本地名称为PackageReference的节点,不限层级 var packageReferences = root.Descendants() .Where(x => x.Name.LocalName == "PackageReference"); foreach (var pkg in packageReferences) { string packageName = pkg.Attribute("Include")?.Value; string version = pkg.Attribute("Version")?.Value ?? pkg.Elements().FirstOrDefault(e => e.Name.LocalName == "Version")?.Value; if (!string.IsNullOrEmpty(packageName) && !string.IsNullOrEmpty(version)) { _packageList.Add(new Package() { App = app, PackageName = packageName, PackageVersion = version, Project = projectName }); } }
注意点
你之前的代码中直接取packageReference.Value的逻辑存在风险:如果PackageReference下有除了Version之外的其他子元素,会把所有子元素的文本拼接返回。修正后优先取Version属性,不存在时显式查找Version子元素取值,逻辑更严谨。
内容的提问来源于stack exchange,提问作者user3132499
相关产品推荐
相关产品推荐

