Rob wrote:
I am moving through an XML document using an XPath Navigator, and I'd like
to be able to get the xpath expression for the location of the current
node from the root node.
I'm not aware of any toolset that provides that functionality, .NET
Framework or otherwise. I think that your question is under-specified: for
any given node in an XML instance document, there may be a very large number
of XPath expressions that all describe the node.
Consider the <c> element in this document:
<a>
<b/>
<b><c/></b>
<b><d/></b>
</a>
Here are a just few of the XPaths that describe it:
/a/b/c, //a/b/c, //b/c, //c, a/b/c[1], /a[1]/b[2]/child:*,
/a/b[d]/preceding-sibling::*/c, //d/ancestor::*[2]//c, /*[1]/*[2]/*[1], etc.
Some of these seem contrived, but each expresses a different relationship
among the nodes. The different relationships could indicate how an
XPathNavigator navigated to particular node.
So, restating the issue, there is no "the" XPath expression for the location
of a node.
When I had a similar need a while back, I created an XmlReader that that
kept track of the currently nested elements and position counts, and exposed
that through a property, so the "canonical" XPath in my custom XmlReader
would look like
/a[1]/b[2]/c[1]
It was not overly complex. This might help you get started.
public class XPathXmlReader : XmlReader
{
private XmlReader reader;
// this ctor allows XmlReaders to be chained
public XPathXmlReader( XmlReader reader ) { this.reader = reader; }
private Stack currentPath;
public string CurrentPath { get { /* ... */ } }
/*
implement all the XmlReader methods in terms of this.reader
and use the currentPath stack to keep track of where you are.
*/
}
Exposing a CurrentPath property for an XPathNavigator would require a
different approach. If performance expense were no object, you could wrap an
XPathNavigator inside of a custom XPathNavigator, and have the custom class
use a combination of methods like MoveToParent and MoveToPrevious (etc.) to
determine the path back to the root from the current node. you could do that
either on a Clone of the object, or navigate back to the current node
position. Obviously, neither of these scale well to large XML documents. You
might also leverage the SelectAncestors method.
Cheers,
Stuart Celarier, Fern Creek