The NamespaceContext is the interface that JAXP provides for establishing the namespace bindings used when an XPath expression is evaluated. Unfortunately, as interfaces go, it leaves a couple of things to be desired.

Try as hard as we may for perfection, the net result of our labors is an amazing variety of imperfectness. We are surprised at our own versatility in being able to fail in so many different ways.

Samuel McChord Crothers

In a namespace well-formed document, the namespace bindings in effect at any given point in the document are well-defined and self-evident. They are the sum of the declarations (and possible undeclarations) that have occurred in the document tree above the point in question (including the declarations on the current element, if the point happens to be an element).

So in the context of this document:

  1<doc xmlns="http://example.org/ns/test"
  2     xmlns:h="http://www.w3.org/1999/xhtml">
  3  <select xpath="//h:body"/>
  4</doc>

The XPath expression in the xpath attribute clearly[1] selects all the elements in the context document that are named “body” and are in the “http://www.w3.org/1999/xhtml” namespace. (It doesn't say anything about how the context document is established, but that's ok.)

One of the problems with using XPath expressions outside the XML context is that we lose this mechanism for determining the namespace bindings. When a QName appears on the side of a bus or in a string in a Java program, what does it mean? Consider:

  1xpath.evaluate ("//t:p", doc);

What's the namespace binding for t:?

The answer, in the case of JAXP, is in the NamespaceContext interface. You can ask the XPath object for a NamespaceContext and subsequently ask that context what's bound to the prefix in question:

  1NamespaceContext nc = xpath.getNamespaceContext();
  2String uri = nc.getNamespaceURI("t");

So far, so good. Now suppose you want to use the XPath API to find all the elements in a document that are named “body” and are in the “http://www.w3.org/1999/xhtml” namespace?

Easy, right? You (1) write the obvious XPath expression and (2) cook up a NamespaceContext that binds the prefix you chose to the HTML namespace and (3) off you go.

So, remind me, how do you do that second part exactly?

You can't.

Well, of course you can, but it's no where near as easy as it should be. The NamespaceContext interface doesn't have an obvious constructor in the JAXP 1.3 API. (And it won't in 1.4 either, but I promise we'll clean this and a bunch of other usability issues up in 1.5.)

To workaround this deficiency, I usually peek inside the implementation and borrow a non-standard class or I implement the NamespaceContext interface in some private, inner class that does just barely enough work to get the job done. The former is completely non-portable and the latter is a tedious pain.

The last time I blushed my way through this explanation with a developer, I decided I could at least implement the interface in some public place so that it could be reused.

I won't be surprised to learn that lots of folks, and lots of frameworks, have already done this. Maybe I could have saved myself a half-day's labor by pointing to one of those, but I also wanted to take NetBeans for a test drive.

The result of my labors is NamespaceContextHelper (and its JavaDoc) which you're welcome to borrow and reuse as you see fit. That package includes the sources, JavaDoc, unit tests, and NetBeans project files.

Speaking of unit tests, I've included a couple of extra tests to highlight common user-errors:

NetBeans 

I've never been a big fan of IDEs, but I have to admit that NetBeans is a pretty nice environment for Java coding. It certainly simplified the construction and running of unit tests and offered lots of useful context-sensitive information. It's only serious flaw is that it isn't Emacs, but I'm not sure I can legitimately hold that against it.

The out-of-the box Emacs keybindings for NetBeans are ok, but they don't seem quite right. Maybe I'm being mislead by my own local Emacs customizations. It's not all my fault though because, for example, “Alt-W”, which should copy the current selection into the clipboard, sometimes drops down the “Window” menu. Bleh. I'm sure I can tweak the bindings, but I haven't tried yet.

Honestly, nice as NetBeans is, I am really, really reluctant to abandon Emacs for anything. I think I'll get a recent version of JDEE and see if I can get it to help me sufficiently to keep me as productive as NetBeans clearly could.

It's not obvious that it's going to be practical, NetBeans is that good.


[1]For the purpose of this essay, let's ignore the issues associated with QNames in content and simply assume that we can recognize them and that they all use the namespace context to determine their bindings.

Comments:

That is #2 on my list of baffling API ommisions, narrowly beaten by JAF's lack of an in-memory DataSource implementation. (google seems to back me up!).

Posted by David Powell on 29 Mar 2006 @ 12:36am UTC #
Seems that Sun is a really big company, where left hand doesn't know what a right hand is doing :-)

At least in my copy of JAXP that comes as a part of JWSDP there is a file NamespaceContextImpl.java in jaxp/samples/XPath directory which provides basic implementation of this interface.

I can see some logic (though little bit perverse I must admit) behind structure of JAXP interfaces, but it seems that they were not designed for daily usage. Why JAXP doesn't support something like:

XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setPrefixMapping("db", "http://docbook.org/ns/docbook");

Actually it was only 3 hours ago, when I was pointing some developer to NamespaceContext implementation for a last time. ;-(

Do you think that in a future we can believe in a complete redesign of JAXP, or it will be only patched and upgraded to support new technlogies in a some way?

To be clear, I don't think that this is your fault, I'm just unhappy with JAXP and with default XML support in a Java platform. And I think that your NamespaceContext implementation will help to many developers (thought ability to do namespace aware XPaths without it, will be even better).

Posted by Jirka Kosek on 29 Mar 2006 @ 03:28pm UTC #

Lot of thanks for share this solution! It was usefull for me.

Posted by Henry2man on 11 Jun 2007 @ 02:52pm UTC #

Worked well for me too. Thanks.

P.S. Thanks for providing the JUnit tests. Without them I could not include it in my source without ruining my code coverage. ;-)

Posted by Justin on 22 Feb 2008 @ 06:15am UTC #
Comments on this essay are closed. Thank you, spammers.