xqueryexist-db

Scope and statically known namespaces in XQuery


consider a library module ctx

xquery version "3.1";

module namespace ctx="module/ctx"; 

declare function ctx:resolve (
    $ctx as function(xs:string) as xs:QName
) as function(xs:string, xs:integer) as function(*)? {
    function ($name as xs:string, $arity as xs:integer) as function(*)? {
        function-lookup($ctx($name), $arity)
    }
};

and a library module a

xquery version "3.1";

module namespace a="module/a"; 

declare function a:f () { "a:f" };

And a main module

xquery version "3.1";

import module namespace a="module/a" at "a.xqm";
import module namespace ctx="module/ctx" at "ctx.xqm";


ctx:resolve(xs:QName(?))("a:f", 0)()

Is it safe to assume that the function reference returned by xs:QName(?) will keep the context in which the namespace a is declared so that the main module will output "a:f"?

This does work in eXist-db (tested on 5.3.0) but I am not sure if this code is portable to other XQuery 3.1 processors.

---- UPDATE ----

What does not work in eXist-db 5.3.0 is

import module namespace ctx="module/ctx" at "ctx.xqm";

declare namespace app = "app";
declare function app:f () { "app:f" };

ctx:resolve(xs:QName(?))("app:f", 0)()

Solution

  • It's an excellent question.

    If you used a named function reference xs:QName#1, then you would find the answer in §3.1.6:

    Furthermore, if the function returned by the evaluation of a NamedFunctionRef has an implementation-dependent implementation, then the implementation of this function is associated with the static context of this NamedFunctionRef expression and with the dynamic context in which the NamedFunctionRef is evaluated.

    That's rather arcane language, but what it means is that the function you get back uses the static and dynamic context of the named function reference itself (and not the context at the point where the function is actually called).

    For a partial function application xs:QName(?) the language is even more impenetrable:

    Implementation: The implementation of F. If this is not an XQuery 3.1 expression then the new function's implementation is associated with a static context and a dynamic context in one of two ways: if F's implementation is already associated with contexts, then those are used; otherwise, SC and DC are used.

    I think the spec is assuming (without justification) that built in functions like xs:QName will have an implementation that is not an XQuery 3.1 expression, so the second sentence applies. I really don't know quite what it intends by the phrase "already associated with contexts" - perhaps it's concerned with the case where F is already a partially applied function. But in any case, I'm reasonably sure that the intent is that "SC and DC are used" - that is, xs:QName(?) works exactly like xs:QName#1, it uses the static and dynamic context at the point where the expression xs:QName(?) is evaluated.

    You're quite right to be concerned that you can't assume that what existing products do is what the spec says must happen. But in this case, I think they are getting it right.