2010-11-24 68 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

相關問題