Monday, September 28, 2009

Just a prefix issue

Everybody who has to deal with XML and XPath in .NET just Run into an issue of accessing elements without having any prefix for the default namespace.

Assume a sample:
You've got an XML-File books.xml as follows:
<books xmlns="urn:books">
 <book>
  <author>It's just me</author>
  <publisheddate>2009-09-25T09:06</publisheddate>
 </book>
</books>

And now? How to access a node?

First attempt:
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");
 
// just build xPath for testing
StringBuilder xPath = new StringBuilder();
XmlNode someNode = doc.DocumentElement.FirstChild.FirstChild;
 
do
{
   xPath.Insert(0, someNode.LocalName);
   xPath.Insert(0, "/");
   someNode = someNode.ParentNode;
}
while (someNode != null && someNode.NodeType != XmlNodeType.Document);
 
// xPath == "/books/book/author"
XmlNode author = doc.DocumentElement.SelectSingleNode(xPath.ToString());

What is the value of author? Right, it's null, hu.

Next attempt, try using XmlNamespaceManager.
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
// try to access with XmlNamespaceManager
XmlNode author = doc.DocumentElement.SelectSingleNode(xPath.ToString(), manager);

What is the value of author? Right, it's still null, hu.

And now?

Try to explain: The Namespace and the Prefix of the used namespace is not defined so xpath could not be resolved.

So try this:
XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
// try to access with XmlNamespaceManager
XmlNode author = doc.DocumentElement.SelectSingleNode(xPath.ToString(), manager);

So try this:
string prefix = "mySample";
if (String.IsNullOrEmpty(manager.LookupPrefix(doc.DocumentElement.NamespaceURI)))
{
   // namespace not added
   manager.AddNamespace(prefix, doc.DocumentElement.NamespaceURI);
}
 
// injecting the namespace
xPath.Replace("/", String.Format("/{0}:", prefix));
 
// xPath is now  "/{mySample}:books/{mySample}:book/{mySample}:author"
author = doc.DocumentElement.SelectSingleNode(xPath.ToString(), manager);

And now, author sould be the selected node.

No comments:

Post a Comment