XPath Context – Where am I in the DOM?

So I was helping a colleague with a code review when I stumbled on something that has been bugging me for a while. I’ve always chalked it up to dom4j – the popular java XML library. It turns out, that it is not dom4j at all – it is XPath. The problem is that when you select a node with an XPath expression, there is context that applies.

I used to think that each node is a self-contained XML document – this is definitely not true.

Considering this quick java app, in a maven project with a POM:

@SuppressWarnings( "all" )
public class DomXpathTest {

public static void main( final String[] args ) throws Exception {
Document document =
DocumentHelper.parseText( FileUtils.readFileToString( new File( "pom.xml" ) ).replaceFirst( "<project.*>", "<project>" ) );

List< Node > nodes = document.selectNodes( "//dependency" );
for( Node node : nodes ) {
//                   Node artifact = node.selectSingleNode( "//artifactId" );
Node artifact = node.selectSingleNode( "./artifactId" );
System.out.println( artifact.asXML() );
System.out.println( "---------------------------------------------" );
}
}
}

Something like this (which is commented out):

node.selectSingleNode( "//artifactId" );

Will in fact select the first artifactId node encountered from the whole document. Which is why, instead, we need to instead use “./” to essentially say “select the first artifactId that is a direct descendant from my current position”. You can also use “.//” or any other variant.

Leave a comment