Xml-SelectNodes with default namespace via XmlNamespaceManager does not work as expected

I have xml with default namespace

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

and want to count the amount <b/>

How do I determine

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

to make the statement true?

I have tried so far (using 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); } 
+10
c # unit-testing xpath
Nov 24 '10 at 21:25
source share
1 answer
 // This will fail with dotnet 3.5sp1. Why? //!!!! Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count); 

This is a FAQ . XPath assumes that any unsigned name is in "no namespace." To select elements that belong to a namespace, in any XPath expression, their names must have a prefix with a prefix associated with that namespace. The AddNamespace() method serves precisely this purpose. It creates a binding between a specific namespace and a specific prefix. Then, if this prefix is ​​used in an XPath expression, the element prefixed by it can be selected.

This is written in the XPath W3C specification : "The QName in the node test expands the expanded name using namespace declarations from the context of the expression. Similarly, the extension is performed for element type names in the start and end tags, except that the default namespace is declared using xmlns, is not used: if the QName does not have a prefix, then the namespace URI is null. "

See this at: w3.org/TR/xpath/#node-tests .

Thus, any unsigned name is considered "no namespace." The XML document provided does not have b elements in the "no namespace", and therefore the XPath //b expression does not select nodes at all.

Using

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

and then :

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

Remember . The whole purpose of registering a namespace is to use a prefix (in this case, x ) in any XPath expression.

+27
Nov 24 '10 at 21:54
source share



All Articles