当标签包含xmlNamespace时,SelectSingleNode返回null

55

我正在将一个包含以下结构的字符串加载到XML文档中:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">                  
  <ItemGroup>
    <Compile Include="clsWorker.cs" />        
  </ItemGroup>      
</Project>

然后我将所有内容加载到一个 XmlDocument 中:

XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(Xml);

然后出现了以下问题:

XmlNode Node = xmldoc.SelectSingleNode("//Compile"); // returns null

如果我从根元素(Project)中删除xmlns属性,它就能正常工作。

我该如何让SelectSingleNode返回相关的元素?

4个回答

98

你应该在调用SelectSingleNode()时使用一个XmlNamespaceManager

XmlNamespaceManager ns = new XmlNamespaceManager(xmldoc.NameTable);
ns.AddNamespace("msbld", "http://schemas.microsoft.com/developer/msbuild/2003");
XmlNode node = xmldoc.SelectSingleNode("//msbld:Compile", ns);

这适用于 SelectNodes 吗? - T.S.
@T.S.,是的。SelectSingleNode("xpath")大致相当于SelectNodes("xpath")[0] - Frédéric Hamidi
3
@Alex,那很随意,我本来可以使用任何东西。重要的是在调用“AddNamespace()”和命名空间前缀中使用相同的名称。 - Frédéric Hamidi
3
@Alex Jolig,假设你的模式都在头文件中指定,你可以像这样动态地添加它们:XmlNamespaceManager ns = new XmlNamespaceManager(xml.NameTable); foreach (XmlAttribute curAttribute in xml.DocumentElement.Attributes) { if (curAttribute.Prefix.Equals("xmlns")) { ns.AddNamespace(curAttribute.LocalName, curAttribute.Value); } } - Ravendarksky
5
如何在源XML一致且同质的情况下省略所有那些使事情变得复杂的名称空间混乱? - TomeeNS
显示剩余2条评论

26

这段话直接摘自MSDN上的SelectSingleNode()文档

注意
如果XPath表达式中不包含前缀,则假定命名空间URI为空命名空间。如果您的XML包括默认命名空间,则仍需向XmlNamespaceManager添加前缀和命名空间URI;否则,您将无法选择节点。有关更多信息,请参阅使用XPath导航选择节点

下面是紧随其后的示例代码:

XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("ab", "http://www.lucernepublishing.com");
XmlNode book = doc.SelectSingleNode("//ab:book", nsmgr);

这并不是一种“隐秘知识”,它只是如此表达:“It's not as if this would be "hidden knowledge". ;-)


7
这样您就不需要指定命名空间:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml("your xml");
XmlNode node = xmlDoc.SelectSingleNode("/*[local-name() = 'Compile']");
XmlNode nodeToImport = xmlDoc2.ImportNode(node, true);
xmlDoc2.AppendChild(nodeToImport);

2
对我来说,必须使用//[local-name,而不是/[local-name。 - Fil

4

'ItemGroup' 可能有多个 'Compile' 子元素,而您特别想要 'Project/ItemGroup' 的 'Compile' 子元素,以下代码将返回所有所需的 'Compile' 子元素,并且不包括其他元素:

XmlDocument projectDoc = new XmlDocument();
projectDoc.Load(projectDocPath);
XmlNamespaceManager ns = new XmlNamespaceManager(projectDoc.NameTable);
ns.AddNamespace("msbld", "http://schemas.microsoft.com/developer/msbuild/2003");
XmlNodeList xnList = projectDoc.SelectNodes(@"/msbld:Project/msbld:ItemGroup/msbld:Compile", ns);

请注意,每个节点级别之前都需要使用“msbld:”命名空间规范。

1
感谢您提醒多个命名空间规范的问题,已点赞。 - Bora

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接