XPath and default namespaces

Say you have a document <root xmlns="http://weblogs.mozillazine.org/weirdal/namespaces/root/"/>. Your default namespace has no prefix for DOM XPath to look up. So if you try to do this:

  var resolver = document.createNSResolver();
var result = document.evaluate("//root", document, resolver,
Components.interfaces.nsIDOMXPathResult.ANY_UNORDERED_NODE_TYPE, null);
alert("Node: " + result.singleNodeValue + "\n");

It’s not going to work. You can’t get to it using Mozilla’s default namespace resolver. Instead, you have to create your own:

  var resolver = {
lookupNamespaceURI: function lookup(aPrefix) {
if (aPrefix == "default") {
return document.documentElement.namespaceURI;
}
}
}
var result = document.evaluate("//default:root", document, resolver,
Components.interfaces.nsIDOMXPathResult.ANY_UNORDERED_NODE_TYPE, null);
alert("Node: " + result.singleNodeValue + "\n");

That will alert a node instead of throwing an exception. It’d really, really be nice if Mozilla’s native XPathNSResolver was smart enough to actually give you a default prefix. Of course, to do that in any sane way, you’d probably have to add a matching lookupPrefix() method, so that if you fed lookupPrefix() a default namespace URI, it would spit back a prefix you could use with your xpath evaluation.

It took me several hours to figure this out, and then only with the help of a devmo-linked tutorial on XPath basics. I want to file a bug on this, but I’m not sure the bug would be valid. If it were valid, I’d fix it myself in a matter of minutes. (It’s worth noting the DOM 3 XPath spec is a Working Group Note, so we’re not under any obligations whatsoever to not do anything to the native resolver.)

UPDATE: Err, I spoke too soon about a matter of minutes, before writing any code on it. If I have <root xmlns="http://weblogs.mozillazine.org/weirdal/namespaces/root/"><real xmlns=http://weblogs.mozillazine.org/weirdal/namespaces/real/"/></root>, then I’m a wee bit hosed at real. I need to work out a JS-based solution first.

UPDATE 2 Hm. “//xmlns:root” seems to work just fine. I remembered something about default namespaces. An attribute xmlns=”foo” has a namespaceURI of “http://www.w3.org/2000/xmlns/”, not null. So that works, and actually fits my needs perfectly. Nothing to see here, move along.

UPDATE 3 I realized about an hour ago that the xmlns: prefix in XPath only covers the namespace URI of the resolver’s initializing node; other nodes with different default namespaces are still lost. Plus, XPath is the wrong solution for the problem I had in mind anyway. Back to the drawing board…

3 thoughts on “XPath and default namespaces”

  1. Breaking the spec is not an option.
    Read the xpath spec, it clearly states that the default namespace is the null namespace.
    This has nothing to do with the DOM non-spec, too.
    (From Alex: Care to point me to the parts of these documents that matter? And this is all about the DOM non-spec; I’m not talking about changing XPath, but our implementation of DOM XPath. Specifically, nsXPathNSResolver.)

  2. I don’t really know enough about XPath to understand what you’re talking about precisely (althought i’m learning) but I’d suggest you file the bug and see what the people in charge of the XPath section have to say. I’ve done this numerous times just in case and only once has my bug been invalid.
    Just my 0.25
    (From Alex: Oh, I’ve filed lots of bugs in areas where I was venturing into new territory, and thought I knew what I was talking about. Blogs don’t crowd the database…)

  3. XPath 1.0 has a null namespace by default. XPath 2.0 allows you to specify a different namespace I believe (or at least XSLT 2.0 lets you).
    It is most convenient to just be able to change the default namespace. This is e.g. possible in PHP 5

Comments are closed.