Edgewall Software

source: trunk/doc/templates.txt

Last change on this file was 1107, checked in by cmlenz, 13 years ago

Improve the template loader docs.

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-rst
File size: 14.5 KB
RevLine 
[534]1.. -*- mode: rst; encoding: utf-8 -*-
2
3========================
4Genshi Templating Basics
5========================
6
7Genshi provides a template engine that can be used for generating either
8markup (such as HTML_ or XML_) or plain text. While both share some of the
9syntax (and much of the underlying implementation) they are essentially
10separate languages.
11
12.. _html: http://www.w3.org/html/
13.. _xml: http://www.w3.org/XML/
14
15This document describes the common parts of the template engine and will be most
16useful as reference to those developing Genshi templates. Templates are XML or
17plain text files that include processing directives_ that affect how the
18template is rendered, and template expressions_ that are dynamically substituted
19by variable data.
20
21
22.. contents:: Contents
23   :depth: 3
24.. sectnum::
25
26--------
27Synopsis
28--------
29
30A Genshi *markup template* is a well-formed XML document with embedded Python
31used for control flow and variable substitution. Markup templates should be
[1098]32used to generate any kind of HTML or XML output, as they provide a number of
33advantages over simple text-based templates (such as automatic escaping of
34variable data).
[534]35
[1098]36The following is a simple Genshi markup template:
[534]37
[614]38.. code-block:: genshi
39
[534]40  <?python
41    title = "A Genshi Template"
42    fruits = ["apple", "orange", "kiwi"]
43  ?>
44  <html xmlns:py="http://genshi.edgewall.org/">
45    <head>
46      <title py:content="title">This is replaced.</title>
47    </head>
48
49    <body>
50      <p>These are some of my favorite fruits:</p>
51      <ul>
52        <li py:for="fruit in fruits">
53          I like ${fruit}s
54        </li>
55      </ul>
56    </body>
57  </html>
58
59This example shows:
60
[1098]61(a) a Python code block in a processing instruction
[534]62(b) the Genshi namespace declaration
63(c) usage of templates directives (``py:content`` and ``py:for``)
64(d) an inline Python expression (``${fruit}``).
65
[614]66The template would generate output similar to this:
[537]67
[614]68.. code-block:: genshi
69
[537]70  <html>
71    <head>
72      <title>A Genshi Template</title>
73    </head>
74
75    <body>
76      <p>These are some of my favorite fruits:</p>
77      <ul>
78        <li>I like apples</li>
79        <li>I like oranges</li>
80        <li>I like kiwis</li>
81      </ul>
82    </body>
83  </html>
84
[1098]85A *text template* is a simple plain text document that can also contain
86embedded Python code. Text templates are intended to be used for simple
87*non-markup* text formats, such as the body of an plain text email. For
88example:
[534]89
[614]90.. code-block:: genshitext
91
[534]92  Dear $name,
93 
94  These are some of my favorite fruits:
95  #for fruit in fruits
96   * $fruit
97  #end
98
99
100----------
101Python API
102----------
103
104The Python code required for templating with Genshi is generally based on the
105following pattern:
106
107* Attain a ``MarkupTemplate`` or ``TextTemplate`` object from a string or
108  file-like object containing the template source. This can either be done
109  directly, or through a ``TemplateLoader`` instance.
110* Call the ``generate()`` method of the template, passing any data that should
111  be made available to the template as keyword arguments.
112* Serialize the resulting stream using its ``render()`` method.
113
[614]114For example:
[534]115
[614]116.. code-block:: pycon
117
[534]118  >>> from genshi.template import MarkupTemplate
119  >>> tmpl = MarkupTemplate('<h1>Hello, $name!</h1>')
120  >>> stream = tmpl.generate(name='world')
[1076]121  >>> print(stream.render('xhtml'))
[534]122  <h1>Hello, world!</h1>
123
[706]124.. note:: See the Serialization_ section of the `Markup Streams`_ page for
125          information on configuring template output options.
126
[614]127Using a text template is similar:
[534]128
[614]129.. code-block:: pycon
130
[534]131  >>> from genshi.template import TextTemplate
132  >>> tmpl = TextTemplate('Hello, $name!')
133  >>> stream = tmpl.generate(name='world')
[1076]134  >>> print(stream)
[534]135  Hello, world!
136
[706]137.. note:: If you want to use text templates, you should consider using the
138          ``NewTextTemplate`` class instead of simply ``TextTemplate``. See
139          the `Text Template Language`_ page.
[534]140
141.. _serialization: streams.html#serialization
[706]142.. _`Text Template Language`: text-templates.html
[534]143.. _`Markup Streams`: streams.html
144
[1107]145Using a `template loader`_ provides the advantage that “compiled” templates are
[534]146automatically cached, and only parsed again when the template file changes. In
147addition, it enables the use of a *template search path*, allowing template
148directories to be spread across different file-system locations. Using a
[614]149template loader would generally look as follows:
[534]150
[614]151.. code-block:: python
152
[534]153  from genshi.template import TemplateLoader
154  loader = TemplateLoader([templates_dir1, templates_dir2])
155  tmpl = loader.load('test.html')
156  stream = tmpl.generate(title='Hello, world!')
[1076]157  print(stream.render())
[534]158
159See the `API documentation <api/index.html>`_ for details on using Genshi via
160the Python API.
161
[1107]162.. _`template loader`: loader.html
[534]163
164.. _`expressions`:
165
166------------------------------------
167Template Expressions and Code Blocks
168------------------------------------
169
170Python_ expressions can be used in text and directive arguments. An expression
171is substituted with the result of its evaluation against the template data.
172Expressions in text (which includes the values of non-directive attributes) need
173to prefixed with a dollar sign (``$``) and usually enclosed in curly braces
174(``{…}``).
175
176.. _python: http://www.python.org/
177
178If the expression starts with a letter and contains only letters, digits, dots,
179and underscores, the curly braces may be omitted. In all other cases, the
180braces are required so that the template processor knows where the expression
[614]181ends:
[534]182
[614]183.. code-block:: pycon
184
[534]185  >>> from genshi.template import MarkupTemplate
186  >>> tmpl = MarkupTemplate('<em>${items[0].capitalize()} item</em>')
[1076]187  >>> print(tmpl.generate(items=['first', 'second']))
[534]188  <em>First item</em>
189
190Expressions support the full power of Python. In addition, it is possible to
191access items in a dictionary using “dotted notation” (i.e. as if they were
192attributes), and vice-versa (i.e. access attributes as if they were items in a
[614]193dictionary):
[534]194
[614]195.. code-block:: pycon
196
[534]197  >>> from genshi.template import MarkupTemplate
198  >>> tmpl = MarkupTemplate('<em>${dict.foo}</em>')
[1076]199  >>> print(tmpl.generate(dict={'foo': 'bar'}))
[534]200  <em>bar</em>
201
202Because there are two ways to access either attributes or items, expressions
203do not raise the standard ``AttributeError`` or ``IndexError`` exceptions, but
204rather an exception of the type ``UndefinedError``. The same kind of error is
[576]205raised when you try to use a top-level variable that is not in the context data.
206See `Error Handling`_ below for details on how such errors are handled.
[534]207
208
[1013]209Escaping
210========
211
212If you need to include a literal dollar sign in the output where Genshi would
213normally detect an expression, you can simply add another dollar sign:
214
215.. code-block:: pycon
216
217  >>> from genshi.template import MarkupTemplate
218  >>> tmpl = MarkupTemplate('<em>$foo</em>') # Wanted "$foo" as literal output
[1076]219  >>> print(tmpl.generate())
[1013]220  Traceback (most recent call last):
221    ...
222  UndefinedError: "foo" not defined
223  >>> tmpl = MarkupTemplate('<em>$$foo</em>')
[1076]224>>> print(tmpl.generate())
[1013]225    <em>$foo</em>
226
227But note that this is not necessary if the characters following the dollar sign
228do not qualify as an expression. For example, the following needs no escaping:
229
230.. code-block:: pycon
231
232  >>> tmpl = MarkupTemplate('<script>$(function() {})</script>')
[1076]233  >>> print(tmpl.generate())
[1013]234  <script>$(function() {})</script>
235
236On the other hand, Genshi will always replace two dollar signs in text with a
237single dollar sign, so you'll need to use three dollar signs to get two in the
238output:
239
240.. code-block:: pycon
241
242  >>> tmpl = MarkupTemplate('<script>$$$("div")</script>')
[1076]243  >>> print(tmpl.generate())
[1013]244  <script>$$("div")</script>
245
246
[534]247.. _`code blocks`:
248
249Code Blocks
250===========
251
[725]252Templates also support full Python code blocks, using the ``<?python ?>``
253processing instruction in XML templates:
[534]254
[614]255.. code-block:: genshi
256
[534]257  <div>
258    <?python
259        from genshi.builder import tag
260        def greeting(name):
[765]261            return tag.b('Hello, %s!' % name) ?>
[534]262    ${greeting('world')}
263  </div>
264
[614]265This will produce the following output:
[534]266
[725]267.. code-block:: xml
[614]268
[534]269  <div>
270    <b>Hello, world!</b>
271  </div>
272
[725]273In text templates (although only those using the new syntax introduced in
274Genshi 0.5), code blocks use the special ``{% python %}`` directive:
275
276.. code-block:: genshitext
277
278  {% python
279      from genshi.builder import tag
280      def greeting(name):
[765]281          return 'Hello, %s!' % name
[725]282  %}
283  ${greeting('world')}
284
285This will produce the following output::
286
287  Hello, world!
288
289
[534]290Code blocks can import modules, define classes and functions, and basically do
291anything you can do in normal Python code. What code blocks can *not* do is to
[722]292produce content that is emitted directly tp the generated output.
[534]293
294.. note:: Using the ``print`` statement will print to the standard output
295          stream, just as it does for other Python code in your application.
296
[576]297Unlike expressions, Python code in ``<?python ?>`` processing instructions can
298not use item and attribute access in an interchangeable manner. That means that
299“dotted notation” is always attribute access, and vice-versa.
[534]300
[576]301The support for Python code blocks in templates is not supposed to encourage
302mixing application code into templates, which is generally considered bad
303design. If you're using many code blocks, that may be a sign that you should
304move such code into separate Python modules.
305
[654]306If you'd rather not allow the use of Python code blocks in templates, you can
307simply set the ``allow_exec`` parameter (available on the ``Template`` and the
308``TemplateLoader`` initializers) to ``False``. In that case Genshi will raise
309a syntax error when a ``<?python ?>`` processing instruction is encountered.
310But please note that disallowing code blocks in templates does not turn Genshi
311into a sandboxable template engine; there are sufficient ways to do harm even
312using plain expressions.
313
[534]314
315.. _`error handling`:
316
317Error Handling
318==============
319
[722]320By default, Genshi raises an ``UndefinedError`` if a template expression
321attempts to access a variable that is not defined:
[534]322
[614]323.. code-block:: pycon
324
[534]325  >>> from genshi.template import MarkupTemplate
326  >>> tmpl = MarkupTemplate('<p>${doh}</p>')
[722]327  >>> tmpl.generate().render('xhtml')
328  Traceback (most recent call last):
329    ...
330  UndefinedError: "doh" not defined
331
332You can change this behavior by setting the variable lookup mode to "lenient".
333In that case, accessing undefined variables returns an `Undefined` object,
334meaning that the expression does not fail immediately. See below for details.
335
336If you need to check whether a variable exists in the template context, use the
337defined_ or the value_of_ function described below. To check for existence of
338attributes on an object, or keys in a dictionary, use the ``hasattr()``,
339``getattr()`` or ``get()`` functions, or the ``in`` operator, just as you would
340in regular Python code:
341
342  >>> from genshi.template import MarkupTemplate
343  >>> tmpl = MarkupTemplate('<p>${defined("doh")}</p>')
[1076]344  >>> print(tmpl.generate().render('xhtml'))
[722]345  <p>False</p>
346
347.. note:: Lenient error handling was the default in Genshi prior to version 0.5.
348          Strict mode was introduced in version 0.4, and became the default in
349          0.5. The reason for this change was that the lenient error handling
350          was masking actual errors in templates, thereby also making it harder
351          to debug some problems.
352
353
354.. _`lenient`:
355
356Lenient Mode
357------------
358
359If you instruct Genshi to use the lenient variable lookup mode, it allows you
360to access variables that are not defined, without raising an ``UndefinedError``.
361
362This mode can be chosen by passing the ``lookup='lenient'`` keyword argument to
363the template initializer, or by passing the ``variable_lookup='lenient'``
364keyword argument to the ``TemplateLoader`` initializer:
365
366.. code-block:: pycon
367
368  >>> from genshi.template import MarkupTemplate
369  >>> tmpl = MarkupTemplate('<p>${doh}</p>', lookup='lenient')
[1076]370  >>> print(tmpl.generate().render('xhtml'))
[534]371  <p></p>
372
373You *will* however get an exception if you try to call an undefined variable, or
[614]374do anything else with it, such as accessing its attributes:
[534]375
[614]376.. code-block:: pycon
377
[534]378  >>> from genshi.template import MarkupTemplate
[722]379  >>> tmpl = MarkupTemplate('<p>${doh.oops}</p>', lookup='lenient')
[1076]380  >>> print(tmpl.generate().render('xhtml'))
[534]381  Traceback (most recent call last):
382    ...
383  UndefinedError: "doh" not defined
384
385If you need to know whether a variable is defined, you can check its type
[614]386against the ``Undefined`` class, for example in a conditional directive:
[534]387
[614]388.. code-block:: pycon
389
[534]390  >>> from genshi.template import MarkupTemplate
[722]391  >>> tmpl = MarkupTemplate('<p>${type(doh) is not Undefined}</p>',
392  ...                       lookup='lenient')
[1076]393  >>> print(tmpl.generate().render('xhtml'))
[534]394  <p>False</p>
395
396Alternatively, the built-in functions defined_ or value_of_ can be used in this
397case.
398
399Custom Modes
400------------
401
402In addition to the built-in "lenient" and "strict" modes, it is also possible to
403use a custom error handling mode. For example, you could use lenient error
404handling in a production environment, while also logging a warning when an
405undefined variable is referenced.
406
407See the API documentation of the ``genshi.template.eval`` module for details.
408
409
410Built-in Functions & Types
411==========================
412
413The following functions and types are available by default in template code, in
414addition to the standard built-ins that are available to all Python code.
415
416.. _`defined`:
417
418``defined(name)``
419-----------------
420This function determines whether a variable of the specified name exists in
421the context data, and returns ``True`` if it does.
422 
423.. _`value_of`:
424
425``value_of(name, default=None)``
426--------------------------------
427This function returns the value of the variable with the specified name if
428such a variable is defined, and returns the value of the ``default``
429parameter if no such variable is defined.
430
431.. _`Markup`:
432
433``Markup(text)``
434----------------
435The ``Markup`` type marks a given string as being safe for inclusion in markup,
436meaning it will *not* be escaped in the serialization stage. Use this with care,
437as not escaping a user-provided string may allow malicious users to open your
438web site to cross-site scripting attacks.
439
440.. _`Undefined`:
441
442``Undefined``
443----------------
444The ``Undefined`` type can be used to check whether a reference variable is
445defined, as explained in `error handling`_.
446
447
448.. _`directives`:
449
450-------------------
451Template Directives
452-------------------
453
454Directives provide control flow functionality for templates, such as conditions
455or iteration. As the syntax for directives depends on whether you're using
456markup or text templates, refer to the
457`XML Template Language <xml-templates.html>`_ or
458`Text Template Language <text-templates.html>`_ pages for information.
Note: See TracBrowser for help on using the repository browser.