Wednesday, 10 December 2008

XPath evaluation in Java using Namespaces

Earlier this year I wrote an article on testing Xpath expressions and XSL transformations in Java. This is no that hard if you know how to do it.

What I did not mention there is how to do xpath-queries on documents with namespaces.
Take for example the following xml:

<?xml version="1.0" encoding="UTF-8" ?>
<XSLBatch xmlns:xsi=""
xsi:schemaLocation=" ../xsd/XSLBatch.xsd"

If you want to do a query on all XSLTransforms, you would probably write an Xpath of the form:

But if you try to do that with the statement:

private XMLDocument xmlDoc;
public NodeList selectNodes(String xpath) throws XSLException {
NodeList nl = this.xmlDoc.selectNodes(xpath);
return nl;

then you find out that the NodeList nl would not deliver you any nodes.
This is because the XML document is of namespace: "" and this is not taken into account in the xpath expression above.
You could use an expression in the form of:

But then: how does the parser know to what Namespace the abbreviation xbt resolves?

You could avoid the problem above with the expression:
This is especially usefull if you have no means of specifying the namespaces you used.
But it makes the expressions very complex and if you need to query on a specific value of an attribute then you're out.

You can resolve this in Java quite easily with a NameSpace resolver. A what? A NameSpace resolver is a class that implements the oracle.xml.parser.v2.NSResolver interface. That is: using the Oracle XML parser.

A sample implementation of the Namespace Resolver is as follows:
package com.m10.xmlfiles;

import java.util.HashMap;

import oracle.xml.parser.v2.NSResolver;

public class XMLNSResolver implements NSResolver{
  private HashMap nsMap = new HashMap();
    public XMLNSResolver() {

   public void addNS(String abbrev, String namespace){
       nsMap.put(abbrev, namespace);
    public String resolveNamespacePrefix(String string) {
        return (String)nsMap.get(string);

As you can see this implementation is fairly simple. It has a HashMap in which you can store your namespaces with an abbreviation as a key.
Since it inmplements the NSResolver interface it must implement the resolveNamespacePrefix. And that one does exactly what you might expect: it gives the namespace back that belongs to the abbreviation.

So if you do the following:
XMLNSResolver nsRes = new XMLNSResolver();
nsRes.addNS("xbt", "");
Then you can do your xpath query as follows:
NodeList nl = this.xmlDoc.selectNodes("/xbt:XSLBatch/xbt:XSLTransform", nsRes);

And that is how this is done.