使用LINQ to XML查询ADMX文件中categories节点返回空结果的问题求助
使用LINQ to XML查询ADMX文件中categories节点返回空结果的问题求助
我最近在尝试用LINQ to XML查询本地组策略的ADMX文件(XML格式),想要提取里面的categories列表,但遇到了一个奇怪的问题:逐行遍历文档能找到category元素,但只要用LINQ查询就返回空结果,想请大家帮忙看看哪里出问题了。
先贴一下我的ADMX文件片段:
<?xml version="1.0" encoding="utf-8"?> <!-- (c) 2006 Microsoft Corporation --> <policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.0" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions"> <policyNamespaces> <target prefix="sharing" namespace="Microsoft.Policies.NetworkSharing" /> <using prefix="windows" namespace="Microsoft.Policies.Windows" /> </policyNamespaces> <resources minRequiredRevision="1.0" /> <categories> <category name="Sharing" displayName="$(string.Sharing)" explainText="$(string.Sharing_Help)"> <parentCategory ref="windows:WindowsComponents" /> </category> <category name="HomeGroup" displayName="$(string.HomeGroup)" explainText="$(string.HomeGroup_Help)"> <parentCategory ref="windows:WindowsComponents" /> </category> </categories> <policies> <policy name="NoInplaceSharing" class="User" displayName="$(string.NoInplaceSharing)" explainText="$(string.NoInplaceSharing_Help)" key="Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" valueName="NoInplaceSharing"> <parentCategory ref="Sharing" /> <supportedOn ref="windows:SUPPORTED_WindowsVista" /> <enabledValue> <decimal value="1" /> </enabledValue> <disabledValue> <decimal value="0" /> </disabledValue> </policy> <policy name="DisableHomeGroup" class="Machine" displayName="$(string.DisableHomeGroup)" explainText="$(string.DisableHomeGroup_Help)" key="Software\Policies\Microsoft\Windows\HomeGroup" valueName="DisableHomeGroup"> <parentCategory ref="HomeGroup" /> <supportedOn ref="windows:SUPPORTED_Windows7" /> <enabledValue> <decimal value="1" /> </enabledValue> <disabledValue> <decimal value="0" /> </disabledValue> </policy> </policies> </policyDefinitions>
我能通过逐行遍历的方式找到category元素:
XDocument doc = XDocument.Load("filename.admx"); IEnumerable<XElement> element = doc.Descendants(); foreach (XElement item in element) { if (item.Name.LocalName == "category") { // 这里能正常进入分支,说明元素存在 } }
但只要尝试用LINQ查询,结果就为空:
var categories = xml.Descendants("policyDefinitions").Elements("categories"); var categories = xml.Descendants("categories").Elements("category"); var categories = xml.Descendants("categories");
有没有过来人能指点一下,这到底是哪里不对啊?
问题原因与解决方案
嗨,这个坑我之前踩过!问题的核心是ADMX文件的元素都属于一个默认XML命名空间,而你直接用元素名称字符串查询时,LINQ to XML会默认查找没有命名空间的元素,自然就匹配不上啦。
你看ADMX根节点policyDefinitions里有这个属性:
xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions"
这个就是整个文档的默认命名空间,所有子元素(包括categories、category)都会自动继承这个命名空间,所以查询时必须带上它。
给你写个正确的查询示例:
// 先定义ADMX的默认命名空间 XNamespace admxNs = "http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions"; XDocument doc = XDocument.Load("filename.admx"); // 方式1:先找到categories节点,再取里面的category元素 var categories = doc.Descendants(admxNs + "categories").Elements(admxNs + "category"); // 方式2:直接查询所有category元素(更简洁) var allCategories = doc.Descendants(admxNs + "category"); // 测试遍历输出 foreach (var category in allCategories) { Console.WriteLine($"分类名称: {category.Attribute("name").Value}"); }
你之前用LocalName能找到元素,是因为LocalName只取元素的本地名称(不带命名空间前缀的部分),所以能匹配到;但像Descendants("categories")这种写法,是在查找完全没有命名空间的<categories>元素,而ADMX里的元素都带默认命名空间,所以返回空。
如果之后还要处理带前缀的元素(比如parentCategory里的windows:WindowsComponents),记得也要定义对应的命名空间:
XNamespace windowsNs = "Microsoft.Policies.Windows"; // 比如解析父分类引用 var parentRef = category.Element(admxNs + "parentCategory").Attribute("ref").Value; // 可以拆分前缀和名称来处理 if (parentRef.StartsWith("windows:")) { var parentName = parentRef.Substring(8); // 这里就可以结合windowsNs做后续处理 }
按照这个方法修改后,你的LINQ查询应该就能正常返回categories列表了!
内容来源于stack exchange
相关产品推荐
相关产品推荐

