带默认命名空间的Xml-SelectNodes通过XmlNamespaceManager不能正常工作

我有一些默认的命名空间的XML

<a xmlns='urn:test.Schema'><b/><b/></a> 

并且要计算<b/>的数量

我该如何定义

 XmlNamespaceManager nsmgr = ???? Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count); 

所以断言成为现实?

我已经尝试过(使用nunit):

 [Test] [Ignore("Why does this not work?")] public void __DoesNotWork_TestSelectWithDefaultNamespace() { // xml to parse with defaultnamespace string xml = @"<a xmlns='urn:test.Schema'><b/><b/></a>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); // fails because xpath does not have the namespace //!!!! Assert.AreEqual(2, doc.SelectNodes("//b").Count); // using XPath defaultnamespace XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); nsmgr.AddNamespace("", "urn:test.Schema"); // This will fail with dotnet 3.5sp1. Why? //!!!! Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count); } [Test] public void TestSelectWithoutNamespaces_Ok() { // xml to parse without namespace string xml = @"<a><b/><b/></a>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); // works ok Assert.AreEqual(2, doc.SelectNodes("//b").Count); // works ok XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count); } [Test] public void TestSelectWithNamespacesPrefixed_Ok() { // xml to parse with defaultnamespace string xml = @"<a xmlns='urn:test.Schema'><b/><b/></a>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); // using XPath namespace via alias "t". works ok but xpath is to complicated XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); nsmgr.AddNamespace("t", doc.DocumentElement.NamespaceURI); Assert.AreEqual(2, doc.SelectNodes("//t:b", nsmgr).Count); } 
 // This will fail with dotnet 3.5sp1. Why? //!!!! Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count); 

这是一个常见问题 。 在XPath中,任何没有前缀的名字都被假定为“没有名字空间”。 为了select属于某个名称空间的元素,在任何XPathexpression式中,其名称都必须以与该名称空间关联的前缀作为前缀。 AddNamespace()方法恰好用于此目的。 它在特定的命名空间和特定的前缀之间创build一个绑定。 然后,如果在XPathexpression式中使用此前缀,则可以select由其前缀的元素。

它是用XPath W3C规范编写的:“使用expression式上下文中的名称空间声明,将节点testing中的QName扩展为扩展名,这与对开始和结束标签中的元素types名称进行扩展相同除了不使用用xmlns声明的默认名称空间:如果QName没有前缀,则名称空间URI为空“。

请参阅: w3.org/TR/xpath/#node-tests

所以,任何没有前缀的名字都被认为是在“no namespace”中。 在提供的XML文档中,“无命名空间”中没有b元素,这就是为什么XPathexpression式//b根本不select节点。

用途

 XmlNamespaceManager nsmanager = new XmlNamespaceManager(doc.NameTable); nsmanager.AddNamespace("x", "urn:test.Schema"); 

后来

 Assert.AreEqual(2, doc.SelectNodes("//x:b", nsmanager).Count); 

请记住 :注册名称空间的目的是为了能够在任何XPathexpression式中使用前缀(在本例中为x )。