MarkLogic external variable access
posted by Steve on
How to examine external variables without risking an error.
External variables can be used to pass data from one xquery to another using the invoke command.
So to use the invoke function the code looks like this:
xquery version "1.0-ml";
let $paramValue := "http://myurl.com"
let $forwardUrl := "/service/my-xquery.xqy"
let $ret := xdmp:invoke($forwardURL,(xs:QName("varurl"), $paramValue),
<options xmlns="xdmp:eval">
<isolation>different-transaction</isolation>
<prevent-deadlocks>false</prevent-deadlocks>
</options>)
This code is passing a url string to another xquery file called my-xquery.xqy for processing. Now lets say that sometimes my-xquery.xqy gets run from a request via a rewriter and sometimes from this invoke.
The problem is you can't reference an external variable unless it has been bound. For this implementation the variable is only bound when it is called from the invoke, so this code will break when called from the rewriter.
xquery version "1.0-ml";
declare variable $varurl as xs:string external;
let $uri := $varurl
As soon as $varurl is reference, an exception is thrown. You could do something like this:
xquery version "1.0-ml";
declare variable $varurl as xs:string external;
declare function xhtml:getURLVar(){
try{
let $returnCode := $varurl
return $returnCode
}catch($e){
let $uri := xdmp:get-request-field("url", ""))
return $uri
}
};
let $uri := xhtml:getURLVar()
But this relies on the try-catch to decide if it is getting the uri from the external var or from the request. Not a good practice because a try-catch is for exceptions not for regular expected conditions.
This third way is the best way.
xquery version "1.0-ml";
declare variable $varurl as xs:string external;
declare function xhtml:getURLVar(){
let $uri := xdmp:get-request-field("url", ""))
let $returnCode := if(fn:string-length(xs:string($uri)) < 1 ) then
$varurl
else
$uri
return $returnCode
};
let $uri := xhtml:getURLVar()
So now the code first checks for the "url" field in the request, if it is empty then the code gets it from the external var $varurl. However, if for some reason the external var is not bound, then you will get an ugly exception on the page. So then it would be appropriate to catch that exception and reroute to some error page.
xquery version "1.0-ml";
declare variable $varurl as xs:string external;
declare function xhtml:getURLVar(){
try{
let $uri := xdmp:get-request-field("url", ""))
let $returnCode := if(fn:string-length(xs:string($uri)) < 1 ) then
$varurl
else
$uri
return $returnCode
}catch($e){
(: put here the default page or error page, this should never happen :)
let $uri := "http://mydomain.com/error-page.xqy"
return $uri
}
};
let $uri := xhtml:getURLVar()
So there you have it, a way to use external variables sometimes and request parameters the other times, cleanly, without exceptions.