226
|
1 .. -*- mode: rst; encoding: utf-8 -*-
|
|
2
|
|
3 ============================
|
230
|
4 Genshi XML Template Language
|
226
|
5 ============================
|
|
6
|
230
|
7 Genshi provides a simple XML-based template language that is heavily inspired
|
226
|
8 by Kid_, which in turn was inspired by a number of existing template languages,
|
|
9 namely XSLT_, TAL_, and PHP_.
|
|
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
|
|
17 This document describes the template language and will be most useful as
|
230
|
18 reference to those developing Genshi templates. Templates are XML files of some
|
226
|
19 kind (such as XHTML) that include processing directives_ (elements or
|
|
20 attributes identified by a separate namespace) that affect how the template is
|
|
21 rendered, and template expressions_ that are dynamically substituted by
|
|
22 variable data.
|
|
23
|
|
24
|
|
25 .. contents:: Contents
|
|
26 :depth: 3
|
|
27 .. sectnum::
|
|
28
|
|
29 ----------
|
|
30 Python API
|
|
31 ----------
|
|
32
|
230
|
33 The Python code required for templating with Genshi is generally based on the
|
226
|
34 following pattern:
|
|
35
|
|
36 * Attain a ``Template`` object from a string or file object containing the
|
|
37 template XML source. This can either be done directly, or through a
|
|
38 ``TemplateLoader`` instance.
|
|
39 * Call the ``generate()`` method of the template, passing any data that should
|
|
40 be made available to the template as keyword arguments.
|
|
41 * Serialize the resulting stream using its ``render()`` method.
|
|
42
|
|
43 For example::
|
|
44
|
230
|
45 from genshi.template import Template
|
226
|
46
|
|
47 tmpl = Template('<h1>$title</h1>')
|
|
48 stream = tmpl.generate(title='Hello, world!')
|
|
49 print stream.render('xhtml')
|
|
50
|
|
51 That code would produce the following output::
|
|
52
|
|
53 <h1>Hello, world!</h1>
|
|
54
|
|
55 However, if you want includes_ to work, you should attain the template instance
|
|
56 through a ``TemplateLoader``, and load the template from a file::
|
|
57
|
230
|
58 from genshi.template import TemplateLoader
|
226
|
59
|
|
60 loader = TemplateLoader([templates_dir])
|
|
61 tmpl = loader.load('test.html')
|
|
62 stream = tmpl.generate(title='Hello, world!')
|
|
63 print stream.render('xhtml')
|
|
64
|
|
65
|
|
66 .. _`expressions`:
|
|
67
|
|
68 --------------------
|
|
69 Template Expressions
|
|
70 --------------------
|
|
71
|
|
72 Python_ expressions can be used in text and attribute values. An expression is
|
|
73 substituted with the result of its evaluation against the template data.
|
|
74 Expressions need to prefixed with a dollar sign (``$``) and usually enclosed in
|
|
75 curly braces (``{…}``).
|
|
76
|
|
77 If the expression starts with a letter and contains only letters and digits,
|
|
78 the curly braces may be omitted. In all other cases, the braces are required so
|
|
79 that the template processors knows where the expression ends::
|
|
80
|
230
|
81 >>> from genshi.template import Context, Template
|
226
|
82 >>> tmpl = Template('<em>${items[0].capitalize()} item</em>')
|
|
83 >>> print tmpl.generate(Context(items=['first', 'second']))
|
|
84 <em>First item</em>
|
|
85
|
|
86 Expressions support the full power of Python. In addition, it is possible to
|
|
87 access items in a dictionary using “dotted notation” (i.e. as if they were
|
|
88 attributes), and vice-versa (i.e. access attributes as if they were items in a
|
|
89 dictionary)::
|
|
90
|
230
|
91 >>> from genshi.template import Context, Template
|
226
|
92 >>> tmpl = Template('<em>${dict.foo}</em>')
|
|
93 >>> print tmpl.generate(Context(dict={'foo': 'bar'}))
|
|
94 <em>bar</em>
|
|
95
|
|
96
|
|
97 .. _`directives`:
|
|
98
|
|
99 -------------------
|
|
100 Template Directives
|
|
101 -------------------
|
|
102
|
|
103 Directives are elements and/or attributes in the template that are identified
|
230
|
104 by the namespace ``http://genshi.edgewall.org/``. They can affect how the
|
|
105 template is rendered in a number of ways: Genshi provides directives for
|
226
|
106 conditionals and looping, among others.
|
|
107
|
|
108 To use directives in a template, the namespace should be declared, which is
|
|
109 usually done on the root element::
|
|
110
|
|
111 <html xmlns="http://www.w3.org/1999/xhtml"
|
230
|
112 xmlns:py="http://genshi.edgewall.org/"
|
226
|
113 lang="en">
|
|
114 ...
|
|
115 </html>
|
|
116
|
|
117 In this example, the default namespace is set to the XHTML namespace, and the
|
230
|
118 namespace for Genshi directives is bound to the prefix “py”.
|
226
|
119
|
|
120 All directives can be applied as attributes, and some can also be used as
|
|
121 elements. The ``if`` directives for conditionals, for example, can be used in
|
|
122 both ways::
|
|
123
|
|
124 <html xmlns="http://www.w3.org/1999/xhtml"
|
230
|
125 xmlns:py="http://genshi.edgewall.org/"
|
226
|
126 lang="en">
|
|
127 ...
|
|
128 <div py:if="foo">
|
|
129 <p>Bar</p>
|
|
130 </div>
|
|
131 ...
|
|
132 </html>
|
|
133
|
|
134 This is basically equivalent to the following::
|
|
135
|
|
136 <html xmlns="http://www.w3.org/1999/xhtml"
|
230
|
137 xmlns:py="http://genshi.edgewall.org/"
|
226
|
138 lang="en">
|
|
139 ...
|
|
140 <py:if test="foo">
|
|
141 <div>
|
|
142 <p>Bar</p>
|
|
143 </div>
|
|
144 </py:if>
|
|
145 ...
|
|
146 </html>
|
|
147
|
|
148 The rationale behind the second form is that directives do not always map
|
|
149 naturally to elements in the template. In such cases, the ``py:strip``
|
|
150 directive can be used to strip off the unwanted element, or the directive can
|
|
151 simply be used as an element.
|
|
152
|
|
153
|
237
|
154 Conditional Sections
|
226
|
155 ====================
|
|
156
|
235
|
157 .. _`py:if`:
|
226
|
158
|
235
|
159 ``py:if``
|
237
|
160 ---------
|
226
|
161
|
235
|
162 The element is only rendered if the expression evaluates to a truth value::
|
226
|
163
|
235
|
164 <div>
|
|
165 <b py:if="foo">${bar}</b>
|
|
166 </div>
|
226
|
167
|
235
|
168 Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this
|
|
169 would produce::
|
|
170
|
|
171 <div>
|
|
172 <b>Hello</b>
|
|
173 </div>
|
|
174
|
|
175 This directive can also be used as an element::
|
|
176
|
|
177 <div>
|
|
178 <py:if test="foo">
|
|
179 <b>${bar}</b>
|
|
180 </py:if>
|
|
181 </div>
|
226
|
182
|
|
183 .. _`py:choose`:
|
|
184 .. _`py:when`:
|
|
185 .. _`py:otherwise`:
|
|
186
|
237
|
187 ``py:choose``
|
|
188 -------------
|
226
|
189
|
237
|
190 The ``py:choose`` directive, in combination with the directives ``py:when``
|
|
191 and ``py:otherwise`` provides advanced contional processing for rendering one
|
226
|
192 of several alternatives. The first matching ``py:when`` branch is rendered, or,
|
|
193 if no ``py:when`` branch matches, the ``py:otherwise`` branch is be rendered.
|
|
194
|
|
195 If the ``py:choose`` directive is empty the nested ``py:when`` directives will
|
|
196 be tested for truth::
|
|
197
|
|
198 <div py:choose="">
|
|
199 <span py:when="0 == 1">0</span>
|
|
200 <span py:when="1 == 1">1</span>
|
|
201 <span py:otherwise="">2</span>
|
|
202 </div>
|
|
203
|
|
204 This would produce the following output::
|
|
205
|
|
206 <div>
|
|
207 <span>1</span>
|
|
208 </div>
|
|
209
|
|
210 If the ``py:choose`` directive contains an expression the nested ``py:when``
|
|
211 directives will be tested for equality to the parent ``py:choose`` value::
|
|
212
|
|
213 <div py:choose="1">
|
|
214 <span py:when="0">0</span>
|
|
215 <span py:when="1">1</span>
|
|
216 <span py:otherwise="">2</span>
|
|
217 </div>
|
|
218
|
|
219 This would produce the following output::
|
|
220
|
|
221 <div>
|
|
222 <span>1</span>
|
|
223 </div>
|
|
224
|
|
225
|
235
|
226 Looping
|
237
|
227 =======
|
226
|
228
|
235
|
229 .. _`py:for`:
|
226
|
230
|
235
|
231 ``py:for``
|
237
|
232 ----------
|
235
|
233
|
|
234 The element is repeated for every item in an iterable::
|
226
|
235
|
|
236 <ul>
|
235
|
237 <li py:for="item in items">${item}</li>
|
226
|
238 </ul>
|
|
239
|
235
|
240 Given ``items=[1, 2, 3]`` in the context data, this would produce::
|
226
|
241
|
|
242 <ul>
|
235
|
243 <li>1</li><li>2</li><li>3</li>
|
226
|
244 </ul>
|
|
245
|
235
|
246 This directive can also be used as an element::
|
226
|
247
|
235
|
248 <ul>
|
|
249 <py:for each="item in items">
|
|
250 <li>${item}</li>
|
|
251 </py:for>
|
|
252 </ul>
|
|
253
|
|
254
|
|
255 Snippet Reuse
|
237
|
256 =============
|
226
|
257
|
|
258 .. _`py:def`:
|
|
259 .. _`macros`:
|
|
260
|
|
261 ``py:def``
|
237
|
262 ----------
|
226
|
263
|
|
264 The ``py:def`` directive can be used to create macros, i.e. snippets of
|
|
265 template code that have a name and optionally some parameters, and that can be
|
|
266 inserted in other places::
|
|
267
|
|
268 <div>
|
|
269 <p py:def="greeting(name)" class="greeting">
|
|
270 Hello, ${name}!
|
|
271 </p>
|
|
272 ${greeting('world')}
|
|
273 ${greeting('everyone else')}
|
|
274 </div>
|
|
275
|
|
276 The above would be rendered to::
|
|
277
|
|
278 <div>
|
|
279 <p class="greeting">
|
|
280 Hello, world!
|
|
281 </p>
|
|
282 <p class="greeting">
|
|
283 Hello, everyone else!
|
|
284 </p>
|
|
285 </div>
|
|
286
|
|
287 If a macro doesn't require parameters, it can be defined as well as called
|
|
288 without the parenthesis. For example::
|
|
289
|
|
290 <div>
|
|
291 <p py:def="greeting" class="greeting">
|
|
292 Hello, world!
|
|
293 </p>
|
|
294 ${greeting}
|
|
295 </div>
|
|
296
|
|
297 The above would be rendered to::
|
|
298
|
|
299 <div>
|
|
300 <p class="greeting">
|
|
301 Hello, world!
|
|
302 </p>
|
|
303 </div>
|
|
304
|
|
305 This directive can also be used as an element::
|
|
306
|
|
307 <div>
|
|
308 <py:def function="greeting(name)">
|
|
309 <p class="greeting">Hello, ${name}!</p>
|
|
310 </py:def>
|
|
311 </div>
|
|
312
|
|
313
|
235
|
314 .. _Match Templates:
|
226
|
315 .. _`py:match`:
|
|
316
|
|
317 ``py:match``
|
237
|
318 ------------
|
226
|
319
|
|
320 This directive defines a *match template*: given an XPath expression, it
|
|
321 replaces any element in the template that matches the expression with its own
|
|
322 content.
|
|
323
|
|
324 For example, the match template defined in the following template matches any
|
|
325 element with the tag name “greeting”::
|
|
326
|
|
327 <div>
|
|
328 <span py:match="greeting">
|
|
329 Hello ${select('@name')}
|
|
330 </span>
|
|
331 <greeting name="Dude" />
|
|
332 </div>
|
|
333
|
|
334 This would result in the following output::
|
|
335
|
|
336 <div>
|
|
337 <span>
|
|
338 Hello Dude
|
|
339 </span>
|
|
340 </div>
|
|
341
|
|
342 Inside the body of a ``py:match`` directive, the ``select(path)`` function is
|
|
343 made available so that parts or all of the original element can be incorporated
|
230
|
344 in the output of the match template. See [wiki:GenshiStream#UsingXPath] for
|
226
|
345 more information about this function.
|
|
346
|
|
347 This directive can also be used as an element::
|
|
348
|
|
349 <div>
|
|
350 <py:match path="greeting">
|
|
351 <span>Hello ${select('@name')}</span>
|
|
352 </py:match>
|
|
353 <greeting name="Dude" />
|
|
354 </div>
|
|
355
|
|
356
|
235
|
357 Variable Binding
|
237
|
358 ================
|
226
|
359
|
|
360 .. _`with`:
|
|
361
|
|
362 ``py:with``
|
237
|
363 -----------
|
226
|
364
|
|
365 The ``py:with`` directive lets you assign expressions to variables, which can
|
|
366 be used to make expressions inside the directive less verbose and more
|
|
367 efficient. For example, if you need use the expression ``author.posts`` more
|
|
368 than once, and that actually results in a database query, assigning the results
|
|
369 to a variable using this directive would probably help.
|
|
370
|
|
371 For example::
|
|
372
|
|
373 <div>
|
|
374 <span py:with="y=7; z=x+10">$x $y $z</span>
|
|
375 </div>
|
|
376
|
|
377 Given ``x=42`` in the context data, this would produce::
|
|
378
|
|
379 <div>
|
|
380 <span>42 7 52</span>
|
|
381 </div>
|
|
382
|
|
383 This directive can also be used as an element::
|
|
384
|
|
385 <div>
|
|
386 <py:with vars="y=7; z=x+10">$x $y $z</py:with>
|
|
387 </div>
|
|
388
|
|
389 Note that if a variable of the same name already existed outside of the scope
|
|
390 of the ``py:with`` directive, it will **not** be overwritten. Instead, it
|
|
391 will have the same value it had prior to the ``py:with`` assignment.
|
230
|
392 Effectively, this means that variables are immutable in Genshi.
|
226
|
393
|
|
394
|
235
|
395 Structure Manipulation
|
237
|
396 ======================
|
235
|
397
|
|
398 .. _`py:attrs`:
|
|
399
|
|
400 ``py:attrs``
|
237
|
401 ------------
|
235
|
402
|
|
403 This directive adds, modifies or removes attributes from the element::
|
|
404
|
|
405 <ul>
|
|
406 <li py:attrs="foo">Bar</li>
|
|
407 </ul>
|
|
408
|
|
409 Given ``foo={'class': 'collapse'}`` in the template context, this would
|
|
410 produce::
|
|
411
|
|
412 <ul>
|
|
413 <li class="collapse">Bar</li>
|
|
414 </ul>
|
|
415
|
|
416 Attributes with the value ``None`` are omitted, so given ``foo={'class': None}``
|
|
417 in the context for the same template this would produce::
|
|
418
|
|
419 <ul>
|
|
420 <li>Bar</li>
|
|
421 </ul>
|
|
422
|
|
423 This directive can only be used as an attribute.
|
|
424
|
|
425
|
|
426 .. _`py:content`:
|
|
427
|
|
428 ``py:content``
|
237
|
429 --------------
|
235
|
430
|
|
431 This directive replaces any nested content with the result of evaluating the
|
|
432 expression::
|
|
433
|
|
434 <ul>
|
|
435 <li py:content="bar">Hello</li>
|
|
436 </ul>
|
|
437
|
|
438 Given ``bar='Bye'`` in the context data, this would produce::
|
|
439
|
|
440 <ul>
|
|
441 <li>Bye</li>
|
|
442 </ul>
|
|
443
|
|
444 This directive can only be used as an attribute.
|
|
445
|
|
446
|
|
447 .. _`py:replace`:
|
|
448
|
|
449 ``py:replace``
|
237
|
450 --------------
|
235
|
451
|
|
452 This directive replaces the element itself with the result of evaluating the
|
|
453 expression::
|
|
454
|
|
455 <div>
|
|
456 <span py:replace="bar">Hello</span>
|
|
457 </div>
|
|
458
|
|
459 Given ``bar='Bye'`` in the context data, this would produce::
|
|
460
|
|
461 <div>
|
|
462 Bye
|
|
463 </div>
|
|
464
|
|
465 This directive can only be used as an attribute.
|
|
466
|
|
467
|
|
468 .. _`py:strip`:
|
|
469
|
|
470 ``py:strip``
|
237
|
471 ------------
|
235
|
472
|
|
473 This directive conditionally strips the top-level element from the output. When
|
|
474 the value of the ``py:strip`` attribute evaluates to ``True``, the element is
|
|
475 stripped from the output::
|
|
476
|
|
477 <div>
|
|
478 <div py:strip="True"><b>foo</b></div>
|
|
479 </div>
|
|
480
|
|
481 This would be rendered as::
|
|
482
|
|
483 <div>
|
|
484 <b>foo</b>
|
|
485 </div>
|
|
486
|
|
487 As a shorthand, if the value of the ``py:strip`` attribute is empty, that has
|
|
488 the same effect as using a truth value (i.e. the element is stripped).
|
|
489
|
|
490
|
226
|
491 .. _order:
|
|
492
|
|
493 Processing Order
|
|
494 ================
|
|
495
|
|
496 It is possible to attach multiple directives to a single element, although not
|
|
497 all combinations make sense. When multiple directives are encountered, they are
|
|
498 processed in the following order:
|
|
499
|
|
500 #. `py:def`_
|
|
501 #. `py:match`_
|
|
502 #. `py:when`_
|
|
503 #. `py:otherwise`_
|
|
504 #. `py:for`_
|
|
505 #. `py:if`_
|
|
506 #. `py:choose`_
|
|
507 #. `py:with`_
|
|
508 #. `py:replace`_
|
|
509 #. `py:content`_
|
|
510 #. `py:attrs`_
|
|
511 #. `py:strip`_
|
|
512
|
|
513
|
|
514 .. _includes:
|
|
515
|
|
516 --------
|
|
517 Includes
|
|
518 --------
|
|
519
|
|
520 To reuse common snippets of template code, you can include other files using
|
|
521 XInclude_.
|
|
522
|
|
523 .. _xinclude: http://www.w3.org/TR/xinclude/
|
|
524
|
|
525 For this, you need to declare the XInclude namespace (commonly bound to the
|
|
526 prefix “xi”) and use the ``<xi:include>`` element where you want the external
|
|
527 file to be pulled in::
|
|
528
|
|
529 <html xmlns="http://www.w3.org/1999/xhtml"
|
230
|
530 xmlns:py="http://genshi.edgewall.org/"
|
226
|
531 xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
532 <xi:include href="base.html" />
|
|
533 ...
|
|
534 </html>
|
|
535
|
|
536 Include paths are relative to the filename of the template currently being
|
|
537 processed. So if the example above was in the file "``myapp/index.html``"
|
|
538 (relative to the template search path), the XInclude processor would look for
|
|
539 the included file at "``myapp/base.html``". You can also use Unix-style
|
|
540 relative paths, for example "``../base.html``" to look in the parent directory.
|
|
541
|
|
542 Any content included this way is inserted into the generated output instead of
|
|
543 the ``<xi:include>`` element. The included template sees the same context data.
|
|
544 `Match templates`_ and `macros`_ in the included template are also available to
|
|
545 the including template after the point it was included.
|
|
546
|
|
547 By default, an error will be raised if an included file is not found. If that's
|
|
548 not what you want, you can specify fallback content that should be used if the
|
|
549 include fails. For example, to to make the include above fail silently, you'd
|
|
550 write:
|
|
551
|
|
552 <xi:include href="base.html"><xi:fallback /></xi:include>
|
|
553
|
230
|
554 See the XInclude_ for more about fallback content. Note though that Genshi
|
226
|
555 currently only supports a small subset of XInclude.
|
|
556
|
230
|
557 Incudes in Genshi are fully dynamic: Just like normal attributes, the `href`
|
226
|
558 attribute accepts expressions_, and directives_ can be used on the
|
|
559 ``<xi:include />`` element just as on any other element, meaning you can do
|
|
560 things like conditional includes::
|
|
561
|
|
562 <xi:include href="${name}.html" py:if="not in_popup"
|
|
563 py:for="name in ('foo', 'bar', 'baz')" />
|
|
564
|
|
565
|
|
566 .. _comments:
|
|
567
|
|
568 --------
|
|
569 Comments
|
|
570 --------
|
|
571
|
|
572 Normal XML/HTML comment syntax can be used in templates::
|
|
573
|
|
574 <!-- this is a comment -->
|
|
575
|
|
576 However, such comments get passed through the processing pipeline and are by
|
|
577 default included in the final output. If that's not desired, prefix the comment
|
|
578 text with an exclamation mark::
|
|
579
|
|
580 <!-- !this is a comment too, but one that will be stripped from the output -->
|
|
581
|
|
582 Note that it does not matter whether there's whitespace before or after the
|
|
583 exclamation mark, so the above could also be written as follows::
|
|
584
|
|
585 <!--! this is a comment too, but one that will be stripped from the output -->
|