I have some xml with default namespace
<a xmlns='urn:test.Schema'><b/><b/></a>
and want to count the number of <b/>
How do I have to define
XmlNamespaceManager nsmgr = ????
Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count);
so that the assert becomes 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);
}
// This will fail with dotnet 3.5sp1. Why? //!!!! Assert.AreEqual(2, doc.SelectNodes("//b", nsmgr).Count);
This is a FAQ. In XPath any unprefixed name is assumed to be in "no namespace". In order to select elements that belong to a namespace, in any XPath expression their names must be prefixed with a prefix that is associated with this namespace. The AddNamespace() method serves exactly 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.
It is written in the XPath W3C spec: "A QName in the node test is expanded into an expanded-name using the namespace declarations from the expression context. This is the same way expansion is done for element type names in start and end-tags except that the default namespace declared with 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 .
So, any unprefixed name is considered to be in "no namespace". In the provided XML document there are no b elements in "no namespace" and this is why the XPath expression //b selects no nodes at all.
Use:
XmlNamespaceManager nsmanager = new XmlNamespaceManager(doc.NameTable);
nsmanager.AddNamespace("x", "urn:test.Schema");
and later:
Assert.AreEqual(2, doc.SelectNodes("//x:b", nsmanager).Count);
Remember: The whole purpose of registering the namespace is to be able to use the prefix (in this case x) in any XPath expression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With