.. -*- mode: rst; encoding: utf-8 -*-

.. _genshi-language:

============================
Genshi XML Template Language
============================

Genshi provides a XML-based template language that is heavily inspired by Kid_,
which in turn was inspired by a number of existing template languages, namely
XSLT_, TAL_, and PHP_.

.. _kid: http://kid-templating.org/
.. _python: http://www.python.org/
.. _xslt: http://www.w3.org/TR/xslt
.. _tal: http://www.zope.org/Wikis/DevSite/Projects/ZPT/TAL
.. _php: http://www.php.net/

This document describes the template language and will be most useful as
reference to those developing Genshi XML templates. Templates are XML files of
some kind (such as XHTML) that include processing directives_ (elements or
attributes identified by a separate namespace) that affect how the template is
rendered, and template expressions that are dynamically substituted by
variable data.

.. _`directives`:

-------------------
Template Directives
-------------------

Directives are elements and/or attributes in the template that are identified
by the namespace ``http://genshi.edgewall.org/``. They can affect how the
template is rendered in a number of ways: Genshi provides directives for
conditionals and looping, among others.

To use directives in a template, the namespace must be declared, which is
usually done on the root element:

.. code-block:: genshi

    ...

In this example, the default namespace is set to the XHTML namespace, and the
namespace for Genshi directives is bound to the prefix “py”.

All directives can be applied as attributes, and some can also be used as
elements. The ``if`` directives for conditionals, for example, can be used in
both ways:

.. code-block:: genshi

    ...

Bar
    
    ...

This is basically equivalent to the following:

.. code-block:: genshi

    ...
    <py:if test="foo">

Bar
      
    </py:if>
    ...

The rationale behind the second form is that directives do not always map
naturally to elements in the template. In such cases, the ``py:strip``
directive can be used to strip off the unwanted element, or the directive can
simply be used as an element.


Conditional Sections
====================

.. _`py:if`:

``py:if``
---------

The element and its content is only rendered if the expression evaluates to a
truth value:

.. code-block:: genshi

    ${bar}

Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this
would produce:

.. code-block:: xml

    Hello

But setting ``foo=False`` would result in the following output:

.. code-block:: xml

This directive can also be used as an element:

.. code-block:: genshi

    <py:if test="foo">
      ${bar}
    </py:if>

.. _`py:choose`:
.. _`py:when`:
.. _`py:otherwise`:

``py:choose``
-------------

The ``py:choose`` directive, in combination with the directives ``py:when``
and ``py:otherwise`` provides advanced conditional processing for rendering one
of several alternatives. The first matching ``py:when`` branch is rendered, or,
if no ``py:when`` branch matches, the ``py:otherwise`` branch is rendered.

If the ``py:choose`` directive is empty the nested ``py:when`` directives will
be tested for truth:

.. code-block:: genshi

    0
    1
    2

This would produce the following output:

.. code-block:: xml

    1

If the ``py:choose`` directive contains an expression the nested ``py:when``
directives will be tested for equality to the parent ``py:choose`` value:

.. code-block:: genshi

    0
    1
    2

This would produce the following output:

.. code-block:: xml

    1

These directives can also be used as elements:

.. code-block:: genshi

  <py:choose test="1">
    <py:when test="0">0</py:when>
    <py:when test="1">1</py:when>
    <py:otherwise>2</py:otherwise>
  </py:choose>

Looping
=======

.. _`py:for`:

``py:for``
----------

The element is repeated for every item in an iterable:

.. code-block:: genshi

- ${item}

Given ``items=[1, 2, 3]`` in the context data, this would produce:

.. code-block:: xml

- 1
- 2
- 3

This directive can also be used as an element:

.. code-block:: genshi

    <py:for each="item in items">
      
- ${item}
    </py:for>

Snippet Reuse
=============

.. _`py:def`:
.. _`macros`:

``py:def``
----------

The ``py:def`` directive can be used to create macros, i.e. snippets of
template code that have a name and optionally some parameters, and that can be
inserted in other places:

.. code-block:: genshi

      Hello, ${name}!
    
    ${greeting('world')}
    ${greeting('everyone else')}

The above would be rendered to:

.. code-block:: xml

      Hello, world!

      Hello, everyone else!

If a macro doesn't require parameters, it can be defined without the 
parenthesis. For example:

.. code-block:: genshi

      Hello, world!
    
    ${greeting()}

The above would be rendered to:

.. code-block:: xml

      Hello, world!

This directive can also be used as an element:

.. code-block:: genshi

    <py:def function="greeting(name)">
      
Hello, ${name}!
    </py:def>

.. _Match Templates:
.. _`py:match`:

``py:match``
------------

This directive defines a *match template*: given an XPath expression, it
replaces any element in the template that matches the expression with its own
content.

For example, the match template defined in the following template matches any
element with the tag name “greeting”:

.. code-block:: genshi

      Hello ${select('@name')}
    
    <greeting name="Dude" />

This would result in the following output:

.. code-block:: xml

      Hello Dude

Inside the body of a ``py:match`` directive, the ``select(path)`` function is
made available so that parts or all of the original element can be incorporated
in the output of the match template. See `Using XPath`_ for more information
about this function.

.. _`Using XPath`: http://genshi.edgewall.org/wiki/Documentation/streams.html#using-xpath

Match templates are applied both to the original markup as well to the
generated markup. The order in which they are applied depends on the order
they are declared in the template source: a match template defined after
another match template is applied to the output generated by the first match
template. The match templates basically form a pipeline.

This directive can also be used as an element:

.. code-block:: genshi

    <py:match path="greeting">
      Hello ${select('@name')}
    </py:match>
    <greeting name="Dude" />

When used this way, the ``py:match`` directive can also be annotated with a
couple of optimization hints. For example, the following informs the matching
engine that the match should only be applied once:

.. code-block:: genshi

  <py:match path="body" once="true">

...
      ${select("*|text()")}
      
...
    
  </py:match>

The following optimization hints are recognized:

+---------------+-----------+-----------------------------------------------+
| Attribute     | Default   | Description                                   |
+===============+===========+===============================================+
| ``buffer``    | ``true``  | Whether the matched content should be         |
|               |           | buffered in memory. Buffering can improve     |
|               |           | performance a bit at the cost of needing more |
|               |           | memory during rendering. Buffering is         |
|               |           | ''required'' for match templates that contain |
|               |           | more than one invocation of the ``select()``  |
|               |           | function. If there is only one call, and the  |
|               |           | matched content can potentially be very long, |
|               |           | consider disabling buffering to avoid         |
|               |           | excessive memory use.                         |
+---------------+-----------+-----------------------------------------------+
| ``once``      | ``false`` | Whether the engine should stop looking for    |
|               |           | more matching elements after the first match. |
|               |           | Use this on match templates that match        |
|               |           | elements that can only occur once in the      |
|               |           | stream, such as the ``<head>`` or ``<body>``  |
|               |           | elements in an HTML template, or elements     |
|               |           | with a specific ID.                           |
+---------------+-----------+-----------------------------------------------+
| ``recursive`` | ``true``  | Whether the match template should be applied  |
|               |           | to its own output. Note that ``once`` implies |
|               |           | non-recursive behavior, so this attribute     |
|               |           | only needs to be set for match templates that |
|               |           | don't also have ``once`` set.                 |
+---------------+-----------+-----------------------------------------------+

.. note:: The ``py:match`` optimization hints were added in the 0.5 release. In
          earlier versions, the attributes have no effect.


Variable Binding
================

.. _`with`:

``py:with``
-----------

The ``py:with`` directive lets you assign expressions to variables, which can
be used to make expressions inside the directive less verbose and more
efficient. For example, if you need use the expression ``author.posts`` more
than once, and that actually results in a database query, assigning the results
to a variable using this directive would probably help.

For example:

.. code-block:: genshi

    $x $y $z

Given ``x=42`` in the context data, this would produce:

.. code-block:: xml

    42 7 52

This directive can also be used as an element:

.. code-block:: genshi

    <py:with vars="y=7; z=x+10">$x $y $z</py:with>

Note that if a variable of the same name already existed outside of the scope
of the ``py:with`` directive, it will **not** be overwritten. Instead, it
will have the same value it had prior to the ``py:with`` assignment.
Effectively, this means that variables are immutable in Genshi.


Structure Manipulation
======================

.. _`py:attrs`:

``py:attrs``
------------

This directive adds, modifies or removes attributes from the element:

.. code-block:: genshi

- Bar

Given ``foo={'class': 'collapse'}`` in the template context, this would
produce:

.. code-block:: xml

- Bar

Attributes with the value ``None`` are omitted, so given ``foo={'class': None}``
in the context for the same template this would produce:

.. code-block:: xml

- Bar

This directive can only be used as an attribute.

.. _`py:content`:

``py:content``
--------------

This directive replaces any nested content with the result of evaluating the
expression:

.. code-block:: genshi

- Hello

Given ``bar='Bye'`` in the context data, this would produce:

.. code-block:: xml

- Bye

This directive can only be used as an attribute.

.. _`py:replace`:

``py:replace``
--------------

This directive replaces the element itself with the result of evaluating the
expression:

.. code-block:: genshi

    Hello

Given ``bar='Bye'`` in the context data, this would produce:

.. code-block:: xml

    Bye

This directive can also be used as an element (since version 0.5):

.. code-block:: genshi

    <py:replace value="title">Placeholder</py:replace>

.. _`py:strip`:

``py:strip``
------------

This directive conditionally strips the top-level element from the output. When
the value of the ``py:strip`` attribute evaluates to ``True``, the element is
stripped from the output:

.. code-block:: genshi

foo

This would be rendered as:

.. code-block:: xml

    foo

As a shorthand, if the value of the ``py:strip`` attribute is empty, that has
the same effect as using a truth value (i.e. the element is stripped).


.. _order:

Processing Order
================

It is possible to attach multiple directives to a single element, although not
all combinations make sense. When multiple directives are encountered, they are
processed in the following order:

#. `py:def`_
#. `py:match`_
#. `py:when`_
#. `py:otherwise`_
#. `py:for`_
#. `py:if`_
#. `py:choose`_
#. `py:with`_
#. `py:replace`_
#. `py:content`_
#. `py:attrs`_
#. `py:strip`_


.. _includes:

--------
Includes
--------

To reuse common snippets of template code, you can include other files using
XInclude_.

.. _xinclude: http://www.w3.org/TR/xinclude/

For this, you need to declare the XInclude namespace (commonly bound to the
prefix “xi”) and use the ``<xi:include>`` element where you want the external
file to be pulled in:

.. code-block:: genshi

    <xi:include href="base.html" />
    ...

Include paths are relative to the filename of the template currently being
processed. So if the example above was in the file "``myapp/index.html``"
(relative to the template search path), the XInclude processor would look for
the included file at "``myapp/base.html``". You can also use Unix-style
relative paths, for example "``../base.html``" to look in the parent directory.

Any content included this way is inserted into the generated output instead of
the ``<xi:include>`` element. The included template sees the same context data.
`Match templates`_ and `macros`_ in the included template are also available to
the including template after the point it was included.

By default, an error will be raised if an included file is not found. If that's
not what you want, you can specify fallback content that should be used if the
include fails. For example, to to make the include above fail silently, you'd
write:

.. code-block:: genshi

  <xi:include href="base.html"><xi:fallback /></xi:include>

See the `XInclude specification`_ for more about fallback content. Note though 
that Genshi currently only supports a small subset of XInclude.

.. _`xinclude specification`: http://www.w3.org/TR/xinclude/


Dynamic Includes
================

Incudes in Genshi are fully dynamic: Just like normal attributes, the `href`
attribute accepts expressions, and directives_ can be used on the
``<xi:include />`` element just as on any other element, meaning you can do
things like conditional includes:

.. code-block:: genshi

  <xi:include href="${name}.html" py:if="not in_popup"
              py:for="name in ('foo', 'bar', 'baz')" />


Including Text Templates
========================

The ``parse`` attribute of the ``<xi:include>`` element can be used to specify
whether the included template is an XML template or a text template (using the
new syntax added in Genshi 0.5):

.. code-block:: genshi

  <xi:include href="myscript.js" parse="text" />

This example would load the ``myscript.js`` file as a ``NewTextTemplate``. See
`text templates`_ for details on the syntax of text templates.

.. _`text templates`: http://genshi.edgewall.org/wiki/Documentation/text-templates.html


.. _comments:

--------
Comments
--------

Normal XML/HTML comment syntax can be used in templates:

.. code-block:: genshi

  

However, such comments get passed through the processing pipeline and are by
default included in the final output. If that's not desired, prefix the comment
text with an exclamation mark:

.. code-block:: genshi

  

Note that it does not matter whether there's whitespace before or after the
exclamation mark, so the above could also be written as follows:

.. code-block:: genshi

  

-------------------------------------
Converting Genshi Templates to Kajiki
-------------------------------------

Kajiki is a fast template engine which is 90% compatible with Genshi,
all of Genshi directives_ work in Kajiki too apart those involved in templates
inheritance as Kajiki uses **blocks** instead of XInclude_ and **XPath**.

Simple templates hierarchies (like the one coming from TurboGears quickstart)
can be moved to Kajiki blocks in a matter of seconds through the Kajiki
``autoblocks`` feature. Autoblocks will automatically create inclusion blocks
whenever a tag with the given name is found. So in case of simple hierarchies
we can easily remove the ``py:match`` and rely on ``autoblocks``.

.. note::

  Please note that this guide only works on version ``2.3.6`` and greater.

.. note::

  It's suggested to try this steps on a newly quickstarted Genshi application
  and then test them on your real apps when you are confident with the
  whole process.

Enabling Autoblocks
===================

Enabling autoblocks in Kajiki involves adding the ``templating.kajiki.xml_autoblocks``
option to your ``app_cfg.py`` with the list of tags that should be considered
autoblocks::

  base_config.renderers.append('kajiki')
  base_config['templating.kajiki.xml_autoblocks'] = ['head', 'body']

  # Set the default renderer
  base_config.default_renderer = 'kajiki'

Restarting your web application you will probably lead to an ``IOError``
regarding TurboGears being unable to find your template. This is because
Kajiki uses ``.xml`` as the default templates extension, while Genshi used
``.html``. What we need to do is add the following line to make Kajiki load
templates from ``.html`` files::

  base_config['templating.kajiki.template_extension'] = '.html'

Adapting the Master Template
============================

The only template we will need to adapt by hand is our ``master.html``
template, everything else will be done automatically. So the effort
of porting an application from Genshi to Kajiki is the same independently
from the size of the application.

First of all let's adapt our ``head`` tag to make it so that the content
from templates that extend our master gets included inside it:

.. code-block:: html+genshi
  :emphasize-lines: 1, 5

    Your generic title goes here

should became:

.. code-block:: html+genshi
  :emphasize-lines: 1, 5

    Your generic title goes here
    <py:blocks name="head"/>

Then we do the same with the ``body`` tag by disabling it as a block and
placing a block with the same name inside of it:

.. code-block:: html+genshi
  :emphasize-lines: 1, 16

    [...]

    <div class="container">
      <!-- Flash messages -->
      <py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
        <div class="row">
          <div class="col-md-8 col-md-offset-2">
            <div py:if="flash" py:replace="Markup(flash)" />
          </div>
        </div>
      </py:with>

      <!-- Main included content -->
      <div py:replace="select('*|text()')"/>
    </div>
  

Which should became:

.. code-block:: html+genshi
  :emphasize-lines: 1, 16

    [...]

    <div class="container">
      <!-- Flash messages -->
      <py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
        <div class="row">
          <div class="col-md-8 col-md-offset-2">
            <div py:if="flash" py:replace="Markup(flash)" />
          </div>
        </div>
      </py:with>

      <!-- Main included content -->
      <py:blocks name="body"/>
    </div>
  

What happened is that we replaced the ``head`` and ``body`` blocks in the
master template (which were created by the ``xml_autoblocks`` option) with
blocks with the same name inside the head and body tags.

Now your application will properly start, but you will get a broken page
due to missing layout, css and so on.

Upgrading Templates
===================

This is because Kajiki doesn't understand the ``xi:include`` command and
so it is not including the ``master.html`` at all. To solve this issue
we can rely on a simple but helpful ``gearbox`` command to patch all our
templates by replacing ``xi:include`` with ``py:extends`` which is used
and recognized by Kajiki.

Just move inside the root of your project and run::

  $ gearbox patch -R '*.html' xi:include -r py:extends

You should get an output similar to::

  7 files matching
  ! Patching /private/tmp/prova/prova/templates/about.html
  ! Patching /private/tmp/prova/prova/templates/data.html
  ! Patching /private/tmp/prova/prova/templates/environ.html
  ! Patching /private/tmp/prova/prova/templates/error.html
  ! Patching /private/tmp/prova/prova/templates/index.html
  ! Patching /private/tmp/prova/prova/templates/login.html
  x Patching /private/tmp/prova/prova/templates/master.html

Which means that all our templates apart from ``master.html`` got patched
properly and now correctly use ``py:extends``.

Restarting your application now should lead to a properly working page
equal to the original Genshi one.

Congratulations, you successfully moved your templates from Genshi
to Kajiki.