2010-11-24 81 views
10

我有一些XML默认命名空间XML的的SelectNodes通过XmlNamespaceManager的默认命名空间无法正常运行

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

,并要计算<b/>

如何做我必须定义

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

这样assert变为true?

我已经试过到目前为止(使用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); 
} 

回答

27
// This will fail with dotnet 3.5sp1. Why? 
//!!!! 
Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count); 

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

这是写在所述XPath W3C spec:“在节点测试的QName是使用命名空间声明从表达式上下文扩展成一个扩展名这是相同的方式扩展为在开始元素类型名称进行除了用xmlns声明的默认名称空间没有被使用外:如果QName没有前缀,则名称空间URI为空“。

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

所以,任何没有前缀的名字都被认为是在“no namespace”中。在提供的XML文档中,“no namespace”中没有b元素,这就是为什么XPath表达式//b根本没有选择节点。

使用

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

后来

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

记住:注册名称空间的全部目的是为了能够使用的前缀(在这种情况下, x)在任何XPath表达式中。

+0

感谢您的回复。你描述了与第三个Unitest TestSelectWithNamespacesPrefixed_Ok()相同的功能。我仍然希望有一个workaroud,而不需要修改xpath-expression – k3b 2010-11-24 22:03:01