Search This Blog

2010-04-30

.NET + XPath + Namespaces

Solved in a subsequent post.

This post is somewhat of a continuation to my previous post. I managed to get LINQ to SQL entities with custom properties serialized fine, however, the output contains XML namespaces which leads me to my next brick wall.

The application that I'm working on uses XPath expressions to match data within the serialization XML. XPath is namespace aware, which means that if you have a structure like this:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<root>
    <level1 xmlns="http://www.bamccaig.com/foo">
        <level2>Useful data!</level2>
    </level1>
</root>
 
 

Then the following XPath expression will NOT grab level2's text node:

/root/level1/level2/text()

The reason? level1 and level2 are in a different namespace than root. I have thus far failed to figure out how to work with this in .NET. In a past experience with this very problem not long ago, I was fortunate enough to be suggested a hack from the kind people on #xml on irc.freenode.net:

/*[local-name()='root']/*[local-name()='level1']/*[local-name()='level2']/text()

The asterisk (*) says to match all nodes (irrespective of namespaces) and the local-name() function returns the tag name (i.e., "root" for <root />). This works, or at least it did in the past, however, as you can imagine it's the Wrong Way(tm) and it's not particularly pretty either. The application I'm working on has a series of XPath expressions to maintain and I don't care to let this hack infect those.

Unfortunately, my attempts to solve this problem have so far failed. The XPathNavigator.Evaluate method accepts an IXmlNamespaceResolver, presumably for this very situation, but I'm unable to coerce it into resolving the namespace. :(

The most frustrating part of this is that the XML that it's [supposed to be] "navigating" is from the serialization process documented in my previous post. The XML was loaded with XmlDocument and the XmlNavigator was created with the XmlDocument's CreateNavigator method. The XmlDocument and XPathNavigator both have a NameTable property, which presumably maps out the namespaces within (it can be used to source an XmlNamespaceManager right in the constructor!), but somehow the XPathNavigator still fails to match to XPath expressions I'm feeding it. And get this: XPathNavigator implements the IXmlNamespaceResolver interface (and no, passing the navigator to the navigator does not work, I tried)!

I'm obviously missing something, but it's going to be nightmare to sort through all of the documentation, especially when I don't even know where to start...

Why, Microsoft?! Why?

Solved in a subsequent post.

No comments:

Post a Comment