Templating

The templating module is used throughout this and most of the other applications which ship with eXist. Its design has one goal: a clean separation of concerns. All views are plain, valid HTML5. They do not include any XQuery or other executable code. Application code should go into separate XQuery modules and will be called automagically by the templating framework.

This document provides a number of simple, working examples. For a detailed description of the features of the templating framework, refer to the documentation.

The templating module scans the HTML for elements with class attributes following a simple convention and tries to translate them into XQuery function calls. In the simplest case, a class attribute which triggers a function call just contains the name of a function in an XQuery library known to the system. For example:

<div class="ex:hello"></div>

The expanded output of this template call is shown below:

Hello World!

Here's the code for the templating function. The two parameters are required for any function to be used by the templating framework:

$node
The HTML node being processed. This is the node with the class attribute which triggered the templating call.
$model
Application data which may have been provided by template functions further up in the document (see below)
declare function ex:hello($node as node()*, $model as map(*)) as element(span) { <span>Hello World!</span> };

Note: instead of putting template calls into class attributes, you can also use the HTML5-compliant method: specify the template call as well as any optional parameters (see the section below) in data attributes:

<div data-template="ex:hello-world" data-template-language="de"></div>

Parameter Injection

Very often, you will also need to pass static parameters to the template. This is done by appending a query string to the template call:

<div class="ex:multiply?n1=5&n2=8"></div>

This calls the following function:

declare function ex:multiply($node as node()*, $model as map(*), $n1 as xs:int, $n2 as xs:int) { $n1 * $n2 };

Parameters can be static or dynamic. Static parameters are specified in the HTML as in the example above. Dynamic parameters are read from the HTTP request or HTTP session. The templating framework automatically tries to determine a value for a given function parameter by looking at those alternatives in turn. If you add "?n1=2&n2=4" to the location URL of this page in your browser, you'll see how the output below will change:

Again, the expanded output is shown below:

40

Annotations

By default, the return value of a templating function will replace the HTML node it was called for. This means the element will be lost unless you copy it. To avoid manually copying the wrapper element, the %templates:wrap annotation does just that.

There's also an annotation %templates:default to define a fallback value for a parameter.

declare %templates:wrap %templates:default("language", "en") function ex:hello-world($node as node(), $model as map(*), $language as xs:string, $user as xs:string) as xs:string { switch($language) case "de" return "Hallo " || $user case "it" return "Ciao " || $user default return "Hello " || $user };

This function could be called with:

<div class="hi ex:hello-world?user=Mary></div>

Please note the extra class "hi", which should color the div. Without %templates:wrap, it would have been lost. Output below:

Hello Mary

Nested Template Calls

Templating calls can be nested, which enables us to build more complex HTML structures. For example:

<table class="ex:addresses"> <tr class="templates:each?from=addresses&amp;to=address"> <td class="ex:print-name"></td> <td class="ex:print-street"></td> <td class="ex:print-city"></td> </tr> </table>

ex:addresses retrieves a set of addresses from the database and puts them into the $model. templates:each iterates through the model items and processes its inner HTML once for each item. Finally, the ex:print-name and friends print out a specific field of the address.

The corresponding XQuery functions are:

declare %templates:wrap function ex:addresses($node as node(), $model as map(*)) as map(*) { map { "addresses" := collection($config:app-root || "/data/addresses")/address } }; declare %templates:wrap function ex:print-name($node as node(), $model as map(*)) { $model("address")/name/string() }; declare %templates:wrap function ex:print-city($node as node(), $model as map(*)) { $model("address")/city/string() }; declare %templates:wrap function ex:print-street($node as node(), $model as map(*)) { $model("address")/street/string() };

Again, the HTML output is displayed below:

Lothar Lärche Vogelstraße 67 Mainz
Elsa Elster Vogelstraße 22 Mainz
Berta Muh An der Viehtränke 13 Wiesbaden
Hans Hase Feldstraße 44 Wiesbaden
Biene Maja Wiesenweg 33 Berlin
Linda Klaus Kopfstraße 5 Heidelberg
Rudi Rüssel An der Viehtränke 24 Frankfurt

Use the Templating from other Contexts

The HTML templating module can also be used outside eXist's default app setup. For example, one may want to call the templating from within a RestXQ module. Because RestXQ uses a separate module for access to HTTP request parameters, you have to supply one additional lookup function for resolving parameters when initializing the templating. The code below demonstrates this:

Demo (Source code)

Source Links