plasTeX 3.0 — A Python Framework for Processing LaTeX Documents

5.3.1 Defining and Using Templates

By default, templates are loaded from the directory where the renderer module was imported from. In addition, the templates from each of the parent renderer class modules are also loaded. This makes it very easy to extend a renderer and add just a few new templates to support the additions that were made.

The template files in the module directories can either contain a single template, corresponding to a single type of node, or several templates. In the first case, the basename of the template file is used as the key to store the template in the renderer, and the extension specifies the template engine to use. Keep in mind that the names of the keys in the renderer correspond to the node names in the document object. The extensions used for all templating engines are shown in the table below.

Engine

Extension

Output Type

Jinja2

.jinja2

Any

ZPT

.html, .htm, .zpt

HTML

 

.xhtml, .xhtm, .xml

XML/XHTML

Python string formatting

.pyt

Any

Python string templates

.st

Any

Kid

.kid

XML/XHTML

Cheetah

.che

XML/XHTML

Genshi

.gen

HTML

The file listing below is an example of a directory of template files. In this case the templates correspond to nodes in the document created by the description environment, the tabular environment, \textbf, and \textit.

description.xml
tabular.xml
textbf.html
textit.html

Since there are a lot of templates that are merely one line, it would be inconvenient to have to create a new file for each template. In cases like this, you can use the ‘.zpts’ extension for collections of ZPT templates, or the ‘.jinja2s’ extension for collections of Jinja2 templates, or more generally ‘.pts’ for collections of various template types. Files with this extension have multiple templates in them. Each template is separated from the next by the template metadata which includes things like the name of the template, the type (xml, html, or text), and can also alias template names to another template in the renderer. The following metadata names are currently supported.

Name

Purpose

engine

the name of the templating engine to use. At the time of this writing, the value could be jinja2, zpt, tal (same as zpt), html (ZPT HTML template), xml (ZPT XML template), jinja2, python (Python formatted string), string (Python string template), kid, cheetah, or genshi.

name

the name or names of the template that is to follow. This name is used as the key in the renderer, and also corresponds to the node name that will be rendered by the template. If more than one name is desired, they are simply separated by spaces.

type

the type of the template: xml, html, or text. XML templates must contain a well-formed XML fragment. HTML templates are more forgiving, but do not support all features of ZPT (see the SimpleTAL documentation).

alias

specifies the name of another template that the given names should be aliased to. This allows you to simply reference another template to use rather than redefining one. For example, you might create a new section heading called \introduction that should render the same way as \section. In this case, you would set the name to “introduction” and the alias to “section”.

There are also some defaults that you can set at the top of the file that get applied to the entire file unles overridden by the meta-data on a particular template.

Name

Purpose

default-engine

the name of the engine to use for all templates in the file.

default-type

the default template type for all templates in the file.

The code sample below shows the basic format of a jinja2s file.

name: textbf bfseries
<b>{{ obj }}</b>

name: textit
<i>{{ obj }}</i>

name: introduction introduction*
alias: section

name: description
<dl>
{% for item in obj %}
  <dt>{{ item.attributes.term }}</dt>
  <dd>{{ item }}</dd>
{% endfor %}
</dl>

The code above is a jinja2s file that contains four templates. Each template begins when a line starts with “name:”. Other directives have the same format (i.e. the name of the directive followed by a colon) and must immediately follow the name directive. The first template definition actually applies to two types of nodes textbf  and bfseries . You can specify ony number of names on the name line. The third template isn’t a template at all; it is an alias. When an alias is specified, the name (or names) given use the same template as the one specified in the alias directive. Notice also that starred versions of a macro can be specified separately. This means that they can use a different template than the un-starred versions of the command. The last template shows a loop example.

Here is an example of using various templates engines in a single file.

name: equation
engine: jinja2
<div class="equation" id="{{ obj.id }}">
  <span class="equation_label">{{ obj.ref }}</span>
  {{ obj }}
</div>

name: textbf
engine: python
<b>%(self)s</b>

name: textit
engine: string
<i>${self}</i>

name: textsc
engine: cheetah
<span class="textsc">${here}</span>

name: textrm
engine: kid
<span class="textrm" py:content="XML(str(here))">normal text</span>

name: textup
engine: genshi
<span class="textup" py:content="markup(here)">upcase text</span>

There are several variables inserted into the template namespace. Here is a list of the variables and the templates that support them.

Object

ZPT/Python Formats/String Template

Jinja2

Cheetah

Kid/Genshi

document node

self  or here 

obj  or here 

here 

here 

parent node

container 

container 

container 

container 

document config

config 

config 

config 

config 

template instance

template 

     

renderer instance

templates 

templates 

templates 

templates 

You’ll notice that Kid and Genshi templates require some extra processing of the variables in order to get the proper markup. By default, these templates escape characters like <, >, and &. In order to get HTML/XML markup from the variables you must wrap them in the code shown in the example above. Hopefully, this limitation will be removed in the future.

When using Jinja2 templates, the default configuration trims white spaces before and after template tags (see trim_blocks and lstrip_blocks in Jinja2’s documentation). Also, when developing Jinja2 templates, inserting {{ debug() }} will launch a python debugger session to allow inspection of the context  variable during rendering.

Template Overrides

It is possible to override the templates located in a renderer’s directory with templates defined elsewhere. This can be done using the --extra-templates option or using the *TEMPLATES environment variable. The “*” in the name *TEMPLATES is a wildcard and must be replaced by the name of the renderer. For example, if you are using the HTML5 renderer, the environment variable would be HTML5TEMPLATES. For the PageTemplate renderer, the environment variable would be PAGETEMPLATETEMPLATES.

The format of this variable is the same as that of the PATH environment variable which means that you can put multiple directory names in this variable. In addition, the environment variables for each of the parent renderers is also used, so that you can use multiple layers of template directories.

You can actually create an entire renderer just using overrides and the PT renderer. Since the PT renderer doesn’t actually define any templates, it is just a framework for defining other XML/HTML renderers, you can simply load the PT renderer and set the PAGETEMPLATETEMPLATES environment variable to the locations of your templates. This method of creating renderers will work for any XML/HTML that doesn’t require any special post-processing.