XQuery/Dynamic Module Loading
Motivation
editYou 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.
Method
editModule import
editWe 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.
Function invocation
editBecause 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()')
Example
editThe 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>
Style A Module
editHere 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>
};
Style A CSS
editbody {
color: blue;
}
Style B Module
editxquery 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>
};
Style B CSS
editbody {
color: red;
}