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.

Share the delectableness

About David Steiner

David has 24 years experience working as software engineer and architect in varying fields, including health care, medical decision support systems, eCommerce, messaging, manufacturing and business simulation, statistical analysis, application server and language design and implementation. He has participated in internet standards work and holds multiple patents for GE Healthcare. He has 3 years of intense MarkLogic and XQuery enterprise experience, including design and implementation of enterprise application deployment. More by David

Leave a comment

blog comments powered by Disqus