How to make XQuery code run in HE but use PE and EE facilities when available?
Added by C. M. Sperberg-McQueen about 2 years ago
I'm not entirely certain of the best place to pose this question; I hope this forum is appropriate.
Consider the case of someone writing an XQuery library who wishes to make it implementation-independent, so that it will run under whatever XQuery engine the user of the library uses: Saxon HE, Saxon PE, Saxon EE, BaseX, eXist-db, ... without, however, generating different versions of the library for different engines. (This question arises from my efforts in that direction on a specific library, on which I can offer more details if need be, but I would like to pose the question in a general form.)
One way to do it is to use only functionality present in all target XQuery engines. That should work, at least in theory, but it means that the library won't be able to do things that it could otherwise easily do (at least in some environments). Like writing multiple files, for example.
Another way to do it is to use fn:function-lookup() to look up functions by name to see whether they are available, before trying to use them. So one might write something like
let $f1 := function-lookup(ns1:f1),
$f2 := function-lookup(ns2:f2)
return if (exists($f1)) then ns1:f1($data)
else if (exists($f2)) then ns2:f2($data)
else <fallback-info/>
There are surely better ways to do this. Perhaps just exists(ns1:f1#1)
would do as well; it's a lot simpler. In XSLT I would use the function-available() function (and the @use-when attribute) rather than this, but function-available() is itself not available in XQuery,.
And in Saxon HE, which does not support higher-order functions, function-lookup() is equally unavailable. as are named function references. So code of the form shown above raises a static error when run with Saxon HE: no function of arity 2 named function-lookup is found. and named function references are not allowed.
Am I missing something simple? Is there any way to inquire, in Saxon HE, about the availability of a function and to use it if available while falling back to other behavior if it's not available?
If there were a QName like expath:higher-order, with the meaning "supports higher-order functions", then one might write
(# expath:higher-order
if (exists(ns1:f1#1))
then ns1:f1($data)
else if (exists(ns2:f2#1))
then ns2:f2($data)
else <fallback-1>This engine supports higher-order functions, but does not have the functions I am looking for.</fallback-1>
#) {
<fallback-2>This fallback for engines that don't support higher-order functions.</fallback-2>
}
but the documentation seems to say that Saxon ignores all pragmas, so this would end up with fallback-2 for all configurations of Saxon, even when ns1:f1 or ns2:f2 were functions supported by Saxon PE or EE.
If the topic of writing implementation-neutral queries has been usefully discussed anywhere, I would be grateful for pointers. If others have experience to share, I will be grateful for any useful advice.
In case it's relevant: at the moment my access to Saxon PE and EE is through Oxygen 24.0, so I am working with Saxon 9.9.1.7.
Replies (3)
Please register to reply
RE: How to make XQuery code run in HE but use PE and EE facilities when available?
-
Added by Martin Honnen about 2 years ago
Since HE 10 you can use higher order functions with HE, as the currently supported versions are 10 and 11 that part of the problem should be resolved in the Saxon world.
RE: How to make XQuery code run in HE but use PE and EE facilities when available?
-
Added by Michael Kay about 2 years ago
As Martin says, higher-order functions (and function-lookup) are now available in Saxon-HE.
Generally XQuery has less support for this kind of thing than XSLT.
You could always, however, consider the age-old technique of putting all your platform-dependent code in a separate module, and loading different versions of that module on different platforms.
RE: How to make XQuery code run in HE but use PE and EE facilities when available?
-
Added by C. M. Sperberg-McQueen about 2 years ago
Thank you, Martin and Michael, for this good news.
I have in fact entertained the plan of (a) hiding all platform dependencies inside of functions and (b) putting all those functions into a library of their own (called, perhaps, problem-children.xqm) so that if it does become necessary to have more than one version of that library, at least the duplication is contained and limited. I admit, though, that I have never gotten very far towards putting it into practice.
If one does end up with platform-dependent code in parallel versions of a single module, is there an XQuery-internal way of loading the correct module? Or does it just turn into an additional task at installation time?
Please register to reply