XQuery/Dynamic Module Loading
Contents |
[edit] Motivation
You want to conditionally import a module. For example the module might provide a list of all the functions to style a web page such as header/footer and breadcrumbs.
[edit] Method
[edit] Module import
We will use the XQuery function util:import-module(). This function has three arguments:
- $namespace: The full URI of the module that you are loading such as http://example.com/my-module
- $prefix: the prefix you want to use to reference each function in the module such as style
- $location: the database path that you will be loading the module from such as an absolute path/db/modules/my-module.xqm or a relative path my-module.xqm
For example the following will import a module called my-module from the /db/modules collection.:
util:import-module(xs:anyURI('http://example.com/my-module'), 'style', xs:anyURI('/db/modules/my-module.xqm'))
The function xs:anyURI is used to cast each string into the URL type.
[edit] Function invocation
Because the namespace is declare dynamically, the imported functions have to be invoked using util:eval. The input to this function is a string containing an XQuery expression. e.g.
util:eval('style:header()')
[edit] Example
The following will randomly load one of two style modules.
xquery version "1.0"; declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=yes indent=yes"; let $module := if (math:random() < 0.5) then util:import-module( xs:anyURI('http://example.com/style-a'), 'style', xs:anyURI('style-a.xqm') ) else util:import-module( xs:anyURI('http://example.com/style-b'), 'style', xs:anyURI('style-b.xqm') ) return <html> <head> <title>Test of Dynamic Module Import</title> {util:eval('style:import-css()')} </head> <body> {util:eval('style:header()')} {util:eval('style:breadcrumb()')} <h1>Test of Dynamic Module Import</h1> {util:eval('style:footer()')} </body> </html>
[edit] Style A Module
Here is an example of a style module. It has four functions. One to import the CSS files, one for the header, one for the navigation breadcrumb and one for the footer.
xquery version "1.0";
module namespace style='http://example.com/style-a';
declare function style:import-css() {
<link type="text/css" rel="stylesheet" href="style-a.css"/>
};
declare function style:header() {
<div class="header">
<h1>Header for Style A</h1>
</div>
};
declare function style:breadcrumb() {
<div class="breadcrumb">
<h1>Breadcrumb for Style A</h1>
</div>
};
declare function style:footer() {
<div class="footer">
<h1>Footer for Style A</h1>
</div>
};
[edit] Style A CSS
body { color: blue; }
[edit] Style B Module
xquery version "1.0";
module namespace style='http://example.com/style-b';
declare function style:import-css() {
<link type="text/css" rel="stylesheet" href="style-b.css"/>
};
declare function style:header() {
<div class="header">
<h1>Header for Style B</h1>
</div>
};
declare function style:breadcrumb() {
<div class="breadcrumb">
<h1>Breadcrumb for Style B</h1>
</div>
};
declare function style:footer() {
<div class="footer">
<h1>Footer for Style B</h1>
</div>
};
[edit] Style B CSS
body { color: red; }