That is the question. Have you ever noticed that when people call built-in XQuery functions like string(), count(), and collection(), they sometimes prefix the function name with "fn:" and sometimes they don't? Why? When is it necessary to include the "fn" prefix, and when is it okay to leave it out? Or perhaps you've noticed that sometimes MarkLogic complains when you leave it out and sometimes it doesn't? This blog post is an attempt to clear up any confusion around this and help you define your own policy or preference on this most important issue that affects us all. (Still reading? Okay, I'll go on.)
The prefix "fn" is special in XQuery, because it's pre-defined to correspond to the namespace URI for built-in XPath functions. The upshot is that the following line is implicit in every XQuery module you write (unless you override it):
This means that you can call functions like fn:string() and fn:concat(), because the "fn" namespace is already defined for you. But if you leave the prefix off a function call, then you'd be relying on the default function namespace, which is often the same as the "fn" namespace, and so it often works. (Ay, there's the rub.) Don't worry, I'll explain what I mean by "often."
But first, it's worth pointing out that things are a bit different in XSLT, where the prefix "fn" does not have any special standing. If you want to write "fn:collection()" in XSLT, you'd need to explicitly bind the "fn" prefix in your stylesheet:
Of course, nobody does that in practice, because "collection()" works just fine, and in fact always works fine without a prefix in XSLT. In other words, the XPath function namespace is always (not just often) the default function namespace in XSLT, and there's no way to override it.
The difference in XQuery is that you can override the default function namespace, using a declaration like this:
If you don't include a line like this in your code, then it's up to your XQuery implementation to determine what the "default default" function namespace is. The XQuery spec "recommends" that implementations set that "default default" to the XPath function namespace (the "default default default"?), but it also allows them to override it. As it happens, MarkLogic is an implementation that overrides it...at least part of the time.
Okay, now I'll explain what I mean by "often." In XQuery, there are two kinds of modules: main modules and library modules. MarkLogic sets the default function namespace to the "fn" namespace for main modules, but for library modules, the default function namespace is set to the module namespace. The nice thing about this is that, in library modules, you aren't immediately forced to use a prefix on the functions that you define:
On the other hand, this means that you need to use the "fn:" prefix on any calls you make to the built-in XPath functions. So a typical scenario is that "collection()" works fine in your main module, but you have to write "fn:collection()" in your library module. This can get annoying if, say, you decide you want to re-use some of the code in your main module by moving it to a library module. Cut-and-paste doesn't cut it; you'll have to add "fn:" in a bunch of places. I think we can all agree that this is a sea of troubles worth taking arms against.
The question is how you want to deal with it. I see two general approaches to avoiding the above pain:
- Always use the "fn:" prefix, OR
- Explicitly declare the "fn" namespace as the default function namespace in library modules, so you never have to use the "fn" prefix.
Both methods are safe, so it largely comes down to personal preference. One thing to note about #2 is that you'll need to start using a prefix on your own module function definitions and function calls (something you have to do anyway when you're calling them from elsewhere). If we really wanted to argue about it, I could give other reasons for one or the other (my preference is #2), but I'll leave that discussion to the comments (bring it on!), lest the native hue of resolution be sicklied o'er...
Before I leave you, I want to make sure you know how to accomplish #2 and forever rid yourself of the need of remembering to type "fn:". Just put the following boilerplate in the prolog of each of your library modules: