Hypertext from XSL templates in Mokvino Web


Mokvino Web is a collection of scripts for GNU Awk, GNU Make and Mokvino which can be used to build and maintain websites.

XSLT files are XML templates that most browsers can transform into HTML. A server process that can create dynamic content (like CGI) can generate application-specific XML instead of HTML directly, to decouple it from layout and style decisions that apply only to hypertext. The XML is prefaced with a processing instruction such as:

<?xml-stylesheet type='text/xsl' href='search.xsl' ?>

This tells the browser to also fetch search.xsl, and use it to transform the XML following the processing instruction into hypertext. To change the layout of the hypertext, re-configure the server process to tag its output with a different XSLT file. The developer of the server process is no longer concerned with layout issues, and the website designer is not concerned with internal application issues.

You can generate XSLT files from Mokvino Web by listing XSLT2HTML as one of the formats:

load(`page')\
PAGE(`langs'=``en-GB'',

`fmts'=``XSLT2HTML'',

`expr'=`qname(`ns'=`http://example.com/ns/app/2016', `meta-index')',

`title'=``My Home Page'',

`body'=``

'p(``Welcome to my world!'')`

'')\

You'll probably want to create a module to assist with some of the boilerplating:

# In etc/templates.m5
shift(

define(`APP_NAMESPACE', ``http://example.com/ns/app/2016'')

define(`QNAME', `qname(`ns'=APP_NAMESPACE, `$$name')', `name')

)

The macro qname ensures that a suitable namespace prefix for your application will be chosen in the generated XSLT. If you're not using namespaces in the application-specific XML, you can forgo it.

load(`page')\
load(`templates')\
PAGE(`langs'=``en-GB'',

`fmts'=``XSLT2HTML'',

`expr'=`QNAME(`meta-index')',

`title'=``My Home Page'',

`body'=``

'p(``Welcome to my world!'')`

'')\

The argument expr specifies the top-level expression to match against, so the template that generates the <html> element and basic page structure looks like this:

<xsl:template match='ns0:meta-index'>
<xsl:element name='html'>
... the usual page elements here ...
</xsl:element>
</xsl:template>

Arguments like head, body and title will contribute to its content the same as they do for HTML. If you need to define other templates, list them in the argument extra:

`extra'=``

'block_template(`QNAME(`entry')', ``...'')`

'block_template(`QNAME(`group')', ``...'')`

'',

(Use inline_template to generate hypertext in an inline context.)

You can then refer to them in other content:

'apply_templates(`QNAME(`entry')')`

Other macros you might use are value_of to generate an element <xsl:value-of>; unescaped_value_of to turn off output escaping; xsl_if to generate either <xsl:if> or <xsl:choose>, depending on the number of tests; xsl_foreach(``expr'', ``content'') to generate <xsl:for-each>.

Variables and parameters

A variable is declared with xsl_var(``root'', ``/*/@root''), yielding:

<xsl:variable name="root" select="/*/@root" />

If you use xsl_varblock(``root'', `value_of(``/*/@root'')') instead, you get a declaration like:

<xsl:variable name="root">
  <xsl:value-of select="/*/@root" />
</xsl:variable>

Parameters are similarly defined with xsl_par and xsl_parblock.

Conditional attributes

Most element attributes come with a counterpart attr.wrap, e.g., checked.wrap for checked on checkbox. Use it if you need to wrap a condition around an entire attribute:

'checkbox(`name'=``enable'', `value'=``yes'', `checked'=, `checked.wrap'=`xsl_if(``@default=\'on\''', `$$$1')')`

Relative URIs

reluri is modified so that it resolves internal links simply by prefixing the value of the XSLT variable $$m5web_base. By default, this is set to the value of the Mokvino macro DOCUMENT_BASE, which is copied from the Make variable DOCUMENT_BASE, which defaults to file://$$(PWD)/$$(WWWPREFIX). If you set DOCUMENT_BASE_EXPR, e.g., like this:

M5FLAGS += -DDOCUMENT_BASE_EXPR='`'"/*/@deploy-base'"

…that will instead set $$m5web_base from a declaration such as:

<xsl:param name='m5web_base' select='/*/@deploy-base' />

…which means that your application-specific XML can provide the URL prefix dynamically. If you're not able to add such an attribute to the XML, you could set DOCUMENT_BASE_INC to an absolute path to load a separately managed XSLT file:

define(`DOCUMENT_BASE_INC', ``/commands/context.php'')