XQuery Code Generation
posted by David on
In order to improve performance and scalability, sometimes it makes sense to turn html (embedded with some tag library or Xquery code) into real XQuery code. It can then be put in the Modules database making it immediately available for use. This is just like what Java Server Pages does!
So how do you do it?
First generate your code: Here is an example function you might call passing in your generated XQuery code as the $content parameter:
declare function generateSomeXqueryWithGenerationWarning($content as xs:string) {
let $doc := fn:string-join((
'(:================================================================
THIS FILE IS GENERATED! DO NOT MODIFY THIS FILE MANUALLY.
IT WILL BE OVERWRITTEN.
GENERATED: ',xs:string(fn:current-dateTime()),'
================================================================:)
',$content,'
(:================================================================
END OF GENERATED FILE
================================================================:)
'
)
,'')}}
return $doc
};
Now with that generated file, call this function to save it either to the Modules database or to the filesystem (whichever your app server is using). The $uri parameter is relative to the modules-root. Don't start it with a slash "/".
declare function saveModuleFile($uri as xs:string,$doc as xs:string) {
if(xdmp:modules-database() = 0) then
(: Save it to the filesystem relative where the app server is pointing to :)
xdmp:save(fn:concat(xdmp:modules-root(),$uri), document { text { $doc })
else
(: Invoke to a module that puts it in the Modules db relative where the app server is pointing to :)
let $ret := xdmp:invoke('saveModuleFile.xqy',
(
xs:QName("uri"), $uri,
xs:QName("doc"), document { text { $doc } }
),
<options xmlns="xdmp:eval">
<database>{ xdmp:modules-database() }</database>
<isolation>different-transaction</isolation>
</options>
)
return ()
};
Remember that the xqy module won't be available in this transaction.
The file that is invoked from this function looks something like this:
xquery version "1.0-ml";
declare option xdmp:mapping "false";
declare variable $uri external;
declare variable $doc external;
xdmp:document-insert($uri,$doc)
The same technique can be used to remove a modules file that is no longer needed.
Now just call in to the generated module from the app server, or use xdmp:function and xdmp:apply to call a function in in it.
It's that easy, the hard part is generating the actual code you want.