Edgewall Software

source: trunk/doc/xml-templates.txt

Last change on this file was 870, checked in by cmlenz, 15 years ago

Clarify description of the py:if directive.

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-rst
File size: 17.3 KB
RevLine 
[283]1.. -*- mode: rst; encoding: utf-8 -*-
2
3============================
[287]4Genshi XML Template Language
[283]5============================
6
[300]7Genshi provides a XML-based template language that is heavily inspired by Kid_,
8which in turn was inspired by a number of existing template languages, namely
9XSLT_, TAL_, and PHP_.
[283]10
11.. _kid: http://kid-templating.org/
12.. _python: http://www.python.org/
13.. _xslt: http://www.w3.org/TR/xslt
14.. _tal: http://www.zope.org/Wikis/DevSite/Projects/ZPT/TAL
15.. _php: http://www.php.net/
16
17This document describes the template language and will be most useful as
[300]18reference to those developing Genshi XML templates. Templates are XML files of
19some kind (such as XHTML) that include processing directives_ (elements or
[283]20attributes identified by a separate namespace) that affect how the template is
[534]21rendered, and template expressions that are dynamically substituted by
[283]22variable data.
23
[534]24See `Genshi Templating Basics <templates.html>`_ for general information on
25embedding Python code in templates.
[283]26
[534]27
[283]28.. contents:: Contents
29   :depth: 3
30.. sectnum::
31
32
33.. _`directives`:
34
35-------------------
36Template Directives
37-------------------
38
39Directives are elements and/or attributes in the template that are identified
[287]40by the namespace ``http://genshi.edgewall.org/``. They can affect how the
41template is rendered in a number of ways: Genshi provides directives for
[283]42conditionals and looping, among others.
43
[478]44To use directives in a template, the namespace must be declared, which is
[614]45usually done on the root element:
[283]46
[614]47.. code-block:: genshi
48
[283]49  <html xmlns="http://www.w3.org/1999/xhtml"
[287]50        xmlns:py="http://genshi.edgewall.org/"
[283]51        lang="en">
52    ...
53  </html>
54
55In this example, the default namespace is set to the XHTML namespace, and the
[287]56namespace for Genshi directives is bound to the prefix “py”.
[283]57
58All directives can be applied as attributes, and some can also be used as
59elements. The ``if`` directives for conditionals, for example, can be used in
[614]60both ways:
[283]61
[614]62.. code-block:: genshi
63
[283]64  <html xmlns="http://www.w3.org/1999/xhtml"
[287]65        xmlns:py="http://genshi.edgewall.org/"
[283]66        lang="en">
67    ...
68    <div py:if="foo">
69      <p>Bar</p>
70    </div>
71    ...
72  </html>
73
[614]74This is basically equivalent to the following:
[283]75
[614]76.. code-block:: genshi
77
[283]78  <html xmlns="http://www.w3.org/1999/xhtml"
[287]79        xmlns:py="http://genshi.edgewall.org/"
[283]80        lang="en">
81    ...
82    <py:if test="foo">
83      <div>
84        <p>Bar</p>
85      </div>
86    </py:if>
87    ...
88  </html>
89
90The rationale behind the second form is that directives do not always map
91naturally to elements in the template. In such cases, the ``py:strip``
92directive can be used to strip off the unwanted element, or the directive can
93simply be used as an element.
94
95
[296]96Conditional Sections
[283]97====================
98
[294]99.. _`py:if`:
[283]100
[294]101``py:if``
[296]102---------
[283]103
[870]104The element and its content is only rendered if the expression evaluates to a
105truth value:
[283]106
[614]107.. code-block:: genshi
108
[294]109  <div>
110    <b py:if="foo">${bar}</b>
111  </div>
[283]112
[294]113Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this
[614]114would produce:
[283]115
[728]116.. code-block:: xml
[614]117
[294]118  <div>
119    <b>Hello</b>
120  </div>
[283]121
[870]122But setting ``foo=False`` would result in the following output:
123
124.. code-block:: xml
125
126  <div>
127  </div>
128
[614]129This directive can also be used as an element:
[283]130
[614]131.. code-block:: genshi
132
[294]133  <div>
134    <py:if test="foo">
135      <b>${bar}</b>
136    </py:if>
137  </div>
[283]138
139.. _`py:choose`:
140.. _`py:when`:
141.. _`py:otherwise`:
142
[296]143``py:choose``
144-------------
[283]145
[296]146The ``py:choose`` directive, in combination with the directives ``py:when``
[496]147and ``py:otherwise`` provides advanced conditional processing for rendering one
[283]148of several alternatives. The first matching ``py:when`` branch is rendered, or,
[496]149if no ``py:when`` branch matches, the ``py:otherwise`` branch is rendered.
[283]150
151If the ``py:choose`` directive is empty the nested ``py:when`` directives will
[614]152be tested for truth:
[283]153
[614]154.. code-block:: genshi
155
[283]156  <div py:choose="">
157    <span py:when="0 == 1">0</span>
158    <span py:when="1 == 1">1</span>
159    <span py:otherwise="">2</span>
160  </div>
161
[614]162This would produce the following output:
[283]163
[728]164.. code-block:: xml
[614]165
[283]166  <div>
167    <span>1</span>
168  </div>
169
170If the ``py:choose`` directive contains an expression the nested ``py:when``
[614]171directives will be tested for equality to the parent ``py:choose`` value:
[283]172
[614]173.. code-block:: genshi
174
[283]175  <div py:choose="1">
176    <span py:when="0">0</span>
177    <span py:when="1">1</span>
178    <span py:otherwise="">2</span>
179  </div>
180
[614]181This would produce the following output:
[283]182
[728]183.. code-block:: xml
[614]184
[283]185  <div>
186    <span>1</span>
187  </div>
188
[850]189These directives can also be used as elements:
[283]190
[850]191.. code-block:: genshi
192
193  <py:choose test="1">
194    <py:when test="0">0</py:when>
195    <py:when test="1">1</py:when>
196    <py:otherwise>2</py:otherwise>
197  </py:choose>
198
[294]199Looping
[296]200=======
[283]201
[294]202.. _`py:for`:
[283]203
[294]204``py:for``
[296]205----------
[283]206
[614]207The element is repeated for every item in an iterable:
[294]208
[614]209.. code-block:: genshi
210
[283]211  <ul>
[294]212    <li py:for="item in items">${item}</li>
[283]213  </ul>
214
[614]215Given ``items=[1, 2, 3]`` in the context data, this would produce:
[283]216
[728]217.. code-block:: xml
[614]218
[283]219  <ul>
[294]220    <li>1</li><li>2</li><li>3</li>
[283]221  </ul>
222
[614]223This directive can also be used as an element:
[283]224
[614]225.. code-block:: genshi
226
[294]227  <ul>
228    <py:for each="item in items">
229      <li>${item}</li>
230    </py:for>
231  </ul>
[283]232
[294]233
234Snippet Reuse
[296]235=============
[294]236
[283]237.. _`py:def`:
238.. _`macros`:
239
240``py:def``
[296]241----------
[283]242
243The ``py:def`` directive can be used to create macros, i.e. snippets of
244template code that have a name and optionally some parameters, and that can be
[614]245inserted in other places:
[283]246
[614]247.. code-block:: genshi
248
[283]249  <div>
250    <p py:def="greeting(name)" class="greeting">
251      Hello, ${name}!
252    </p>
253    ${greeting('world')}
254    ${greeting('everyone else')}
255  </div>
256
[614]257The above would be rendered to:
[283]258
[728]259.. code-block:: xml
[614]260
[283]261  <div>
262    <p class="greeting">
263      Hello, world!
264    </p>
265    <p class="greeting">
266      Hello, everyone else!
267    </p>
268  </div>
269
[478]270If a macro doesn't require parameters, it can be defined without the
[614]271parenthesis. For example:
[283]272
[614]273.. code-block:: genshi
274
[283]275  <div>
276    <p py:def="greeting" class="greeting">
277      Hello, world!
278    </p>
[478]279    ${greeting()}
[283]280  </div>
281
[614]282The above would be rendered to:
[283]283
[728]284.. code-block:: xml
[614]285
[283]286  <div>
287    <p class="greeting">
288      Hello, world!
289    </p>
290  </div>
291
[614]292This directive can also be used as an element:
[283]293
[614]294.. code-block:: genshi
295
[283]296  <div>
297    <py:def function="greeting(name)">
298      <p class="greeting">Hello, ${name}!</p>
299    </py:def>
300  </div>
301
302
[294]303.. _Match Templates:
[283]304.. _`py:match`:
305
306``py:match``
[296]307------------
[283]308
309This directive defines a *match template*: given an XPath expression, it
310replaces any element in the template that matches the expression with its own
311content.
312
313For example, the match template defined in the following template matches any
[614]314element with the tag name “greeting”:
[283]315
[614]316.. code-block:: genshi
317
[283]318  <div>
319    <span py:match="greeting">
320      Hello ${select('@name')}
321    </span>
322    <greeting name="Dude" />
323  </div>
324
[614]325This would result in the following output:
[283]326
[728]327.. code-block:: xml
[614]328
[283]329  <div>
330    <span>
331      Hello Dude
332    </span>
333  </div>
334
335Inside the body of a ``py:match`` directive, the ``select(path)`` function is
336made available so that parts or all of the original element can be incorporated
[545]337in the output of the match template. See `Using XPath`_ for more information
338about this function.
[283]339
[545]340.. _`Using XPath`: streams.html#using-xpath
341
[810]342Match templates are applied both to the original markup as well to the
343generated markup. The order in which they are applied depends on the order
344they are declared in the template source: a match template defined after
345another match template is applied to the output generated by the first match
346template. The match templates basically form a pipeline.
347
[614]348This directive can also be used as an element:
[283]349
[614]350.. code-block:: genshi
351
[283]352  <div>
353    <py:match path="greeting">
354      <span>Hello ${select('@name')}</span>
355    </py:match>
356    <greeting name="Dude" />
357  </div>
358
[718]359When used this way, the ``py:match`` directive can also be annotated with a
360couple of optimization hints. For example, the following informs the matching
361engine that the match should only be applied once:
[283]362
[718]363.. code-block:: genshi
364
365  <py:match path="body" once="true">
366    <body py:attrs="select('@*')">
367      <div id="header">...</div>
368      ${select("*|text()")}
369      <div id="footer">...</div>
370    </body>
371  </py:match>
372
373The following optimization hints are recognized:
374
375+---------------+-----------+-----------------------------------------------+
376| Attribute     | Default   | Description                                   |
377+===============+===========+===============================================+
[816]378| ``buffer``    | ``true``  | Whether the matched content should be         |
379|               |           | buffered in memory. Buffering can improve     |
380|               |           | performance a bit at the cost of needing more |
381|               |           | memory during rendering. Buffering is         |
382|               |           | ''required'' for match templates that contain |
383|               |           | more than one invocation of the ``select()``  |
384|               |           | function. If there is only one call, and the  |
385|               |           | matched content can potentially be very long, |
386|               |           | consider disabling buffering to avoid         |
387|               |           | excessive memory use.                         |
388+---------------+-----------+-----------------------------------------------+
[718]389| ``once``      | ``false`` | Whether the engine should stop looking for    |
390|               |           | more matching elements after the first match. |
391|               |           | Use this on match templates that match        |
392|               |           | elements that can only occur once in the      |
393|               |           | stream, such as the ``<head>`` or ``<body>``  |
394|               |           | elements in an HTML template, or elements     |
395|               |           | with a specific ID.                           |
396+---------------+-----------+-----------------------------------------------+
397| ``recursive`` | ``true``  | Whether the match template should be applied  |
398|               |           | to its own output. Note that ``once`` implies |
399|               |           | non-recursive behavior, so this attribute     |
400|               |           | only needs to be set for match templates that |
401|               |           | don't also have ``once`` set.                 |
402+---------------+-----------+-----------------------------------------------+
403
404.. note:: The ``py:match`` optimization hints were added in the 0.5 release. In
405          earlier versions, the attributes have no effect.
406
407
[294]408Variable Binding
[296]409================
[294]410
411.. _`with`:
412
413``py:with``
[296]414-----------
[294]415
416The ``py:with`` directive lets you assign expressions to variables, which can
417be used to make expressions inside the directive less verbose and more
418efficient. For example, if you need use the expression ``author.posts`` more
419than once, and that actually results in a database query, assigning the results
420to a variable using this directive would probably help.
421
[614]422For example:
[294]423
[614]424.. code-block:: genshi
425
[294]426  <div>
427    <span py:with="y=7; z=x+10">$x $y $z</span>
428  </div>
429
[614]430Given ``x=42`` in the context data, this would produce:
[294]431
[728]432.. code-block:: xml
[614]433
[294]434  <div>
435    <span>42 7 52</span>
436  </div>
437
[614]438This directive can also be used as an element:
[294]439
[614]440.. code-block:: genshi
441
[294]442  <div>
443    <py:with vars="y=7; z=x+10">$x $y $z</py:with>
444  </div>
445
446Note that if a variable of the same name already existed outside of the scope
447of the ``py:with`` directive, it will **not** be overwritten. Instead, it
448will have the same value it had prior to the ``py:with`` assignment.
449Effectively, this means that variables are immutable in Genshi.
450
451
452Structure Manipulation
[296]453======================
[294]454
455.. _`py:attrs`:
456
457``py:attrs``
[296]458------------
[294]459
[614]460This directive adds, modifies or removes attributes from the element:
[294]461
[614]462.. code-block:: genshi
463
[294]464  <ul>
465    <li py:attrs="foo">Bar</li>
466  </ul>
467
468Given ``foo={'class': 'collapse'}`` in the template context, this would
[614]469produce:
[294]470
[728]471.. code-block:: xml
[614]472
[294]473  <ul>
474    <li class="collapse">Bar</li>
475  </ul>
476
477Attributes with the value ``None`` are omitted, so given ``foo={'class': None}``
[614]478in the context for the same template this would produce:
[294]479
[728]480.. code-block:: xml
[614]481
[294]482  <ul>
483    <li>Bar</li>
484  </ul>
485
486This directive can only be used as an attribute.
487
488
489.. _`py:content`:
490
491``py:content``
[296]492--------------
[294]493
494This directive replaces any nested content with the result of evaluating the
[614]495expression:
[294]496
[614]497.. code-block:: genshi
498
[294]499  <ul>
500    <li py:content="bar">Hello</li>
501  </ul>
502
[614]503Given ``bar='Bye'`` in the context data, this would produce:
[294]504
[728]505.. code-block:: xml
[614]506
[294]507  <ul>
508    <li>Bye</li>
509  </ul>
510
511This directive can only be used as an attribute.
512
513
[283]514.. _`py:replace`:
515
516``py:replace``
[296]517--------------
[283]518
519This directive replaces the element itself with the result of evaluating the
[614]520expression:
[283]521
[614]522.. code-block:: genshi
523
[283]524  <div>
525    <span py:replace="bar">Hello</span>
526  </div>
527
[614]528Given ``bar='Bye'`` in the context data, this would produce:
[283]529
[728]530.. code-block:: xml
[614]531
[283]532  <div>
533    Bye
534  </div>
535
[773]536This directive can also be used as an element (since version 0.5):
[283]537
[773]538.. code-block:: genshi
[283]539
[773]540  <div>
541    <py:replace value="title">Placeholder</py:replace>
542  </div>
543
544
545
[283]546.. _`py:strip`:
547
548``py:strip``
[296]549------------
[283]550
551This directive conditionally strips the top-level element from the output. When
552the value of the ``py:strip`` attribute evaluates to ``True``, the element is
[614]553stripped from the output:
[283]554
[614]555.. code-block:: genshi
556
[283]557  <div>
558    <div py:strip="True"><b>foo</b></div>
559  </div>
560
[614]561This would be rendered as:
[283]562
[728]563.. code-block:: xml
[614]564
[283]565  <div>
566    <b>foo</b>
567  </div>
568
569As a shorthand, if the value of the ``py:strip`` attribute is empty, that has
570the same effect as using a truth value (i.e. the element is stripped).
571
572
573.. _order:
574
575Processing Order
576================
577
578It is possible to attach multiple directives to a single element, although not
579all combinations make sense. When multiple directives are encountered, they are
580processed in the following order:
581
582#. `py:def`_
583#. `py:match`_
584#. `py:when`_
585#. `py:otherwise`_
586#. `py:for`_
587#. `py:if`_
588#. `py:choose`_
589#. `py:with`_
590#. `py:replace`_
591#. `py:content`_
592#. `py:attrs`_
593#. `py:strip`_
594
595
596.. _includes:
597
598--------
599Includes
600--------
601
602To reuse common snippets of template code, you can include other files using
603XInclude_.
604
605.. _xinclude: http://www.w3.org/TR/xinclude/
606
607For this, you need to declare the XInclude namespace (commonly bound to the
608prefix “xi”) and use the ``<xi:include>`` element where you want the external
[614]609file to be pulled in:
[283]610
[614]611.. code-block:: genshi
612
[283]613  <html xmlns="http://www.w3.org/1999/xhtml"
[287]614        xmlns:py="http://genshi.edgewall.org/"
[283]615        xmlns:xi="http://www.w3.org/2001/XInclude">
616    <xi:include href="base.html" />
617    ...
618  </html>
619
620Include paths are relative to the filename of the template currently being
621processed. So if the example above was in the file "``myapp/index.html``"
622(relative to the template search path), the XInclude processor would look for
623the included file at "``myapp/base.html``". You can also use Unix-style
624relative paths, for example "``../base.html``" to look in the parent directory.
625
626Any content included this way is inserted into the generated output instead of
627the ``<xi:include>`` element. The included template sees the same context data.
628`Match templates`_ and `macros`_ in the included template are also available to
629the including template after the point it was included.
630
631By default, an error will be raised if an included file is not found. If that's
632not what you want, you can specify fallback content that should be used if the
633include fails. For example, to to make the include above fail silently, you'd
[614]634write:
[283]635
[614]636.. code-block:: genshi
637
[283]638  <xi:include href="base.html"><xi:fallback /></xi:include>
639
[338]640See the `XInclude specification`_ for more about fallback content. Note though
641that Genshi currently only supports a small subset of XInclude.
[283]642
[338]643.. _`xinclude specification`: http://www.w3.org/TR/xinclude/
644
[726]645
646Dynamic Includes
647================
648
[287]649Incudes in Genshi are fully dynamic: Just like normal attributes, the `href`
[534]650attribute accepts expressions, and directives_ can be used on the
[283]651``<xi:include />`` element just as on any other element, meaning you can do
[614]652things like conditional includes:
[283]653
[614]654.. code-block:: genshi
655
[283]656  <xi:include href="${name}.html" py:if="not in_popup"
657              py:for="name in ('foo', 'bar', 'baz')" />
658
659
[726]660Including Text Templates
661========================
662
663The ``parse`` attribute of the ``<xi:include>`` element can be used to specify
664whether the included template is an XML template or a text template (using the
665new syntax added in Genshi 0.5):
666
667.. code-block:: genshi
668
669  <xi:include href="myscript.js" parse="text" />
670
671This example would load the ``myscript.js`` file as a ``NewTextTemplate``. See
672`text templates`_ for details on the syntax of text templates.
673
674.. _`text templates`: text-templates.html
675
676
[283]677.. _comments:
678
679--------
680Comments
681--------
682
[614]683Normal XML/HTML comment syntax can be used in templates:
[283]684
[614]685.. code-block:: genshi
686
[283]687  <!-- this is a comment -->
688
689However, such comments get passed through the processing pipeline and are by
690default included in the final output. If that's not desired, prefix the comment
[614]691text with an exclamation mark:
[283]692
[614]693.. code-block:: genshi
694
[283]695  <!-- !this is a comment too, but one that will be stripped from the output -->
696
697Note that it does not matter whether there's whitespace before or after the
[614]698exclamation mark, so the above could also be written as follows:
[283]699
[614]700.. code-block:: genshi
701
[283]702  <!--! this is a comment too, but one that will be stripped from the output -->
Note: See TracBrowser for help on using the repository browser.