HTML Templating Module
The HTML templating framework makes creating XQuery applications that produce HTML pages more easy.
The main goal of the HTML templating framework is a clean separation of concerns. Generating entire pages in XQuery is quick and dirty, but makes maintenance and code sharing difficult. Ideally people should be able to look at the HTML view of an application and modify its look and feel without knowing XQuery. The application logic, written in XQuery, should be kept separate. Likewise, the XQuery developer should only have to deal with the minimal amount of HTML (generated dynamically).
The templating module also handles most of the HTTP processing an application requires. It does so using sophisticated features like automatic parameter injection and type conversion. The goal was to remove repeating code like:
In fact you should not see many calls to the HTTP request or session module inside a templating function. This is all handled by parameter injection.
Working examples for the templating module can be found in the demo application.
The templating module is based mainly on conventions. Wherever possible it tries to make a best guess instead of requiring additional code or annotations. This works as long as the conventions used are sufficiently clear.
The input for the templating framework is always a plain HTML file. The module scans the
HTML view for elements with
data-template, see below)
attributes following a simple convention and tries to translate them into XQuery function
calls. By using class attributes, the HTML remains sufficiently clean and does not get messed
up with application code. A web designer could take the HTML files and work on it without
being bothered by the extra class names.
In the simplest case, a template call inside a class attribute is just the name of a function known in the XQuery context. To start with the usual "Hello world" example:
When the module encounters demo:hello, it will try to find a function named "demo:hello"
in all the modules known to the XQuery. If this function's signature follows a certain
convention (see below), it will be called and the
<div> will either be replaced or
enhanced by whatever the function returns.
Please note that the additional class "grey-box" does not interfere with the template call
and is ignored by the templating framework. The templating framework will only take a closer
look at class names which follow the
grey-box is probably be a class used for CSS styling, so we don't want to
It is possible to pass static parameters to a template call. These must be encoded as URI
parameters, for instance:
demo:hello?language=de. A static parameter will be
passed to the XQuery function as a fallback value, if it cannot be determined by looking at
the HTTP context (see below).
Instead of "abusing" class attributes to encode template calls or other
application-specific information, HTML5 provides a standard method for adding data to an
data-* attributes. This approach is supported in the
templating framework (beginning with version 0.3.0 of the shared-resources package).
data-* attributes must follow the function naming pattern. The
templating function to call has to be specified in an
optional parameters go into one or more attributes
For example the previous example could be rewritten as:
The templating framework supports both alternatives.
A templating function is an ordinary XQuery function in a module which takes at least two parameters of a specific type. Additional parameters are allowed. If a function does not follow this convention it will be ignored by the framework.
For example, our "Hello world!" function could be defined as follows:
The two required parameters are
$nodecontains the HTML node currently being processed: in this case, the
$modelis an XQuery map with application data. It will be empty for now, but we'll see later why it is important.
The additional parameters in the example above,
$user, will be injected automatically. The templating framework tries to make a
best guess how to fill those parameters with values. It checks the following 3 contexts for
parameters with the same name (in the order below):
if the current HTTP request contains a (non-empty) parameter with the same name as the parameter variable, this is used to set the value of the variable
if the HTTP session contains an attribute with the same name as the parameter variable, this is used to set the value of the variable
if the static parameters passed to the template call contain a parameter matching the variable name, it will be used
If neither 1 nor 2 lead to a non-empty value, the function signature will be checked for
%templates:default("name", "value1", ..., "valueN"). See
If "language" is passed as a parameter in the HTTP request, it will overwrite the static parameter we provided because the HTTP request is checked first.
The templating framework will also attempt automatic type conversion for all parameters.
If the parameter has a declared type of
xs:integer, it will try to cast a
parameter it finds into an integer. If the type is
node(), the parameter value
will be parsed into XML. These conversions may fail and this results in an error passing a
parameter with the wrong type.
Our "Hello world" example above does not preserve the div from which it was called, but
replaces it with a new one which lacks the "grey-box" class. This is the default behavior. To
preserve the enclosing div, we should add the XQuery annotation
to the function signature.
Another annotation can be used to provide a default value for a parameter:
%templates:default("parameter", "value1", "value2", ...). The first parameter
of the annotation must match the name of the parameter variable. All other parameters in the
annotation are used as values for the variable.
For example, set
en if the value cannot be
Because of the
%templates:wrap we can now remove the wrapping
in the function and just return a string now.
In a more complex application, a view will have many templating functions which all access the same data. For example, take a typical search page: there might be one HTML element to display the number of hits, one to show the query, and another one for printing out the results. All those components need to access the search result. How to do this in a templating framework?
This is where the
$model parameter comes into play. It is passed to all
template functions and they can add data to it. This is available to nested template calls.
For example a search page:
demo:result-list occur inside the
demo:search. They are nested
demo:search will perform the actual search operation, based on
the parameters passed by the user. Instead of directly printing the search result in HTML, it
delegates this to the nested templates.
demo:search can be implemented as:
demo:search differs from the functions we have seen so far in that it returns an
XQuery map and not HTML or some atomic type. If a templating function returns a map, the
templating framework will proceed as follows:
Add the returned map to the current
$modelmap (adding it to the map keeps entries produced by any ancestor templates)
resume processing the children of the current HTML node
demo:hit-count can now access the query results in
Inside a templating function, you can also call
node()*, $model as map(*)) to have the templating module process the given node
You need to make sure you are not running into an endless loop by calling
templates:process on the currently processed node.
A common pattern is to trigger
templates:process on the children of the
This is comparable to calling
<xsl:apply-templates> in XSLT and will have the
same effect as returning a map (see the section above), but with your templating function
having full control.
For example, it is sometimes necessary to first process all the descendant nodes of the
current element, then apply some action to the processed tree. The documentation app has a
config:expand-links, which scans the final document tree for links
and expands them. The function is implemented as follows:
The templating module is entirely implemented in XQuery. It provides a single public
templates:apply. A complete main module which calls the templating
framework to process an HTML file passed in the HTTP request body could look as
This module would be called from the URL rewriting controller. For example, we could add a
controller.xql to pass any .html resource to the above main query
The only part of the main module code which might look a bit unusual is the inline lookup function: the templating module uses dynamic function calls to execute template functions in application modules. But unfortunately, XQuery modules can only "see" functions in their own context. There is therefore no way for the templating module to determine what functions are defined in application modules which are outside its context. So need to "help" it by providing a callback function to resolve function references. The lookup function is defined in the main context and can access all the modules imported into the main module.
Normally you can just copy and paste the main module code as given above. To adopt it to your own application, just import your application modules and you're done.
The "New Application" templates in eXide already include the HTML templating module and
configures the URL rewriting to call this for any path ending in
Using eXide is therefore the easiest way to get started with the templating framework.
Please consult the Getting Started with Web Application Development guide.
If you generate your application with eXide, a copy of the HTML templating module will be included, so you can customize it. If you rather want to make sure you have the latest version of the templating module: the shared-resources application also exports the module. This will always be the latest version. You could therefore define a dependency on the shared-resources app (see the packaging documentation). You can now just import the module by its namespace URI, but without specifying a location:
The documentation and demo applications all read the templating module from shared-resources.
The templating module defines a number of general-purpose templating functions which are described below.
templates:surround is probably the most powerful one and used by almost all
Includes the content of the resource given by
path into the current
path is always interpreted relative to the current application
directory or collection.
Retrieve the sequence identified by the map key
from in the
$model map. If it exists, iterate over the items in its value (as a sequence)
and process any nested content once. During each iteration, the current item is added to the
$model map using the key
Conditionally includes content only if the given request parameter is set and not empty.
Conditionally includes content only if the given request parameter is not set or empty.
Surrounds its content with the contents of the XML resource specified in
at parameter determines where the content is inserted
into the surrounding XML. It should match an existing HTML
id in the
using parameter is optional and specifies the
id of an
element in the
with resource. The current content will be surrounded by this
element. If this parameter is missing, the entire document given in
The surround template instruction is used by all pages of the Demo
application. The header, basic page structure and menus are the same for all pages. Each
page only contains a simple
<div> with a template instruction:
The instruction takes the content of the current element and injects it into the template page.
<select> elements: checks the HTTP request for a
parameter matching the name of the form control and fills it into the value of an input or
selects the corresponding option of a select.
Commonly used with an
<a> element: opens the document referenced in the
href attribute in eXide.