Mercurial > genshi > mirror
annotate doc/xml-templates.txt @ 430:77e99857b351 trunk
Moved the `builder` document into the API docs.
author | cmlenz |
---|---|
date | Thu, 22 Mar 2007 17:14:09 +0000 |
parents | 691dd56c0dd0 |
children | 97544725bb7f |
rev | line source |
---|---|
226 | 1 .. -*- mode: rst; encoding: utf-8 -*- |
2 | |
3 ============================ | |
230 | 4 Genshi XML Template Language |
226 | 5 ============================ |
6 | |
241
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
7 Genshi provides a XML-based template language that is heavily inspired by Kid_, |
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
8 which in turn was inspired by a number of existing template languages, namely |
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
9 XSLT_, TAL_, and PHP_. |
226 | 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 | |
241
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
18 reference to those developing Genshi XML templates. Templates are XML files of |
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
19 some kind (such as XHTML) that include processing directives_ (elements or |
226 | 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 | |
241
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
36 * Attain a ``MarkupTemplate`` object from a string or file object containing |
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
37 the template XML source. This can either be done directly, or through a |
226 | 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 | |
241
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
45 from genshi.template import MarkupTemplate |
226 | 46 |
241
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
47 tmpl = MarkupTemplate('<h1>$title</h1>') |
226 | 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 | |
429
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
68 ------------------------------------ |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
69 Template Expressions and Code Blocks |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
70 ------------------------------------ |
226 | 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 | |
394 | 77 If the expression starts with a letter and contains only letters, digits, dots, |
78 and underscores, the curly braces may be omitted. In all other cases, the | |
79 braces are required so that the template processor knows where the expression | |
80 ends:: | |
226 | 81 |
241
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
82 >>> from genshi.template import MarkupTemplate |
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
83 >>> tmpl = MarkupTemplate('<em>${items[0].capitalize()} item</em>') |
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
84 >>> print tmpl.generate(items=['first', 'second']) |
226 | 85 <em>First item</em> |
86 | |
87 Expressions support the full power of Python. In addition, it is possible to | |
88 access items in a dictionary using “dotted notation” (i.e. as if they were | |
89 attributes), and vice-versa (i.e. access attributes as if they were items in a | |
90 dictionary):: | |
91 | |
241
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
92 >>> from genshi.template import MarkupTemplate |
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
93 >>> tmpl = MarkupTemplate('<em>${dict.foo}</em>') |
4d81439bc097
* Added basic documentation for the text-based template language.
cmlenz
parents:
237
diff
changeset
|
94 >>> print tmpl.generate(dict={'foo': 'bar'}) |
226 | 95 <em>bar</em> |
96 | |
429
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
97 Because there are two ways to access either attributes or items, expressions |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
98 do not raise the standard ``AttributeError`` or ``IndexError`` exceptions, but |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
99 rather an exception of the type ``UndefinedError``. The same kind of error is |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
100 raised when you try to access a top-level variable that is not in the context |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
101 data. |
244 | 102 |
103 | |
429
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
104 .. _`code blocks`: |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
105 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
106 Code Blocks |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
107 =========== |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
108 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
109 XML templates also support full Python code blocks using the ``<?python ?>`` |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
110 processing instruction:: |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
111 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
112 <div> |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
113 <?python |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
114 from genshi.builder import tag |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
115 def greeting(name): |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
116 return tag.b('Hello, %s!' % name') ?> |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
117 ${greeting('world')} |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
118 </div> |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
119 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
120 This will produce the following output:: |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
121 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
122 <div> |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
123 <b>Hello, world!</b> |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
124 </div> |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
125 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
126 Code blocks can import modules, define classes and functions, and basically do |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
127 anything you can do in normal Python code. What code blocks can *not* do is to |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
128 produce content that is included directly in the generated page. |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
129 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
130 .. note:: Using the ``print`` statement will print to the standard output |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
131 stream, just as it does for other Python code in your application. |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
132 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
133 This feature is not supposed to encourage mixing application code into |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
134 templates, which is generally considered bad design. If you're using many code |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
135 blocks, that me be a sign that you should move such code into separate Python |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
136 modules. |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
137 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
138 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
139 Built-in Functions & Types |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
140 ========================== |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
141 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
142 The following functions and types are available by default in template code, in |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
143 addition to the standard built-ins that are available to all Python code. |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
144 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
145 ``defined(name)`` |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
146 ----------------- |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
147 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
148 This function determines whether a variable of the specified name exists in |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
149 the context data, and returns ``True`` if it does. |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
150 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
151 ``value_of(name, default=None)`` |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
152 -------------------------------- |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
153 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
154 This function returns the value of the variable with the specified name if |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
155 such a variable is defined, and returns the value of the ``default`` |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
156 parameter if no such variable is defined. |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
157 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
158 ``Markup(text)`` |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
159 ---------------- |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
160 |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
161 The ``Markup`` type marks a given string as being safe for inclusion in markup, |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
162 meaning it will *not* be escaped in the serialization stage. Use this with care, |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
163 as not escaping a user-provided string may allow malicious users to open your |
691dd56c0dd0
Updated docs for code blocks and changed error handling.
cmlenz
parents:
404
diff
changeset
|
164 web site to cross-site scripting attacks. |
244 | 165 |
226 | 166 |
167 .. _`directives`: | |
168 | |
169 ------------------- | |
170 Template Directives | |
171 ------------------- | |
172 | |
173 Directives are elements and/or attributes in the template that are identified | |
230 | 174 by the namespace ``http://genshi.edgewall.org/``. They can affect how the |
175 template is rendered in a number of ways: Genshi provides directives for | |
226 | 176 conditionals and looping, among others. |
177 | |
394 | 178 To use directives in a template, the namespace must be declared, which is |
226 | 179 usually done on the root element:: |
180 | |
181 <html xmlns="http://www.w3.org/1999/xhtml" | |
230 | 182 xmlns:py="http://genshi.edgewall.org/" |
226 | 183 lang="en"> |
184 ... | |
185 </html> | |
186 | |
187 In this example, the default namespace is set to the XHTML namespace, and the | |
230 | 188 namespace for Genshi directives is bound to the prefix “py”. |
226 | 189 |
190 All directives can be applied as attributes, and some can also be used as | |
191 elements. The ``if`` directives for conditionals, for example, can be used in | |
192 both ways:: | |
193 | |
194 <html xmlns="http://www.w3.org/1999/xhtml" | |
230 | 195 xmlns:py="http://genshi.edgewall.org/" |
226 | 196 lang="en"> |
197 ... | |
198 <div py:if="foo"> | |
199 <p>Bar</p> | |
200 </div> | |
201 ... | |
202 </html> | |
203 | |
204 This is basically equivalent to the following:: | |
205 | |
206 <html xmlns="http://www.w3.org/1999/xhtml" | |
230 | 207 xmlns:py="http://genshi.edgewall.org/" |
226 | 208 lang="en"> |
209 ... | |
210 <py:if test="foo"> | |
211 <div> | |
212 <p>Bar</p> | |
213 </div> | |
214 </py:if> | |
215 ... | |
216 </html> | |
217 | |
218 The rationale behind the second form is that directives do not always map | |
219 naturally to elements in the template. In such cases, the ``py:strip`` | |
220 directive can be used to strip off the unwanted element, or the directive can | |
221 simply be used as an element. | |
222 | |
223 | |
237 | 224 Conditional Sections |
226 | 225 ==================== |
226 | |
235 | 227 .. _`py:if`: |
226 | 228 |
235 | 229 ``py:if`` |
237 | 230 --------- |
226 | 231 |
235 | 232 The element is only rendered if the expression evaluates to a truth value:: |
226 | 233 |
235 | 234 <div> |
235 <b py:if="foo">${bar}</b> | |
236 </div> | |
226 | 237 |
235 | 238 Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this |
239 would produce:: | |
240 | |
241 <div> | |
242 <b>Hello</b> | |
243 </div> | |
244 | |
245 This directive can also be used as an element:: | |
246 | |
247 <div> | |
248 <py:if test="foo"> | |
249 <b>${bar}</b> | |
250 </py:if> | |
251 </div> | |
226 | 252 |
253 .. _`py:choose`: | |
254 .. _`py:when`: | |
255 .. _`py:otherwise`: | |
256 | |
237 | 257 ``py:choose`` |
258 ------------- | |
226 | 259 |
237 | 260 The ``py:choose`` directive, in combination with the directives ``py:when`` |
404 | 261 and ``py:otherwise`` provides advanced conditional processing for rendering one |
226 | 262 of several alternatives. The first matching ``py:when`` branch is rendered, or, |
404 | 263 if no ``py:when`` branch matches, the ``py:otherwise`` branch is rendered. |
226 | 264 |
265 If the ``py:choose`` directive is empty the nested ``py:when`` directives will | |
266 be tested for truth:: | |
267 | |
268 <div py:choose=""> | |
269 <span py:when="0 == 1">0</span> | |
270 <span py:when="1 == 1">1</span> | |
271 <span py:otherwise="">2</span> | |
272 </div> | |
273 | |
274 This would produce the following output:: | |
275 | |
276 <div> | |
277 <span>1</span> | |
278 </div> | |
279 | |
280 If the ``py:choose`` directive contains an expression the nested ``py:when`` | |
281 directives will be tested for equality to the parent ``py:choose`` value:: | |
282 | |
283 <div py:choose="1"> | |
284 <span py:when="0">0</span> | |
285 <span py:when="1">1</span> | |
286 <span py:otherwise="">2</span> | |
287 </div> | |
288 | |
289 This would produce the following output:: | |
290 | |
291 <div> | |
292 <span>1</span> | |
293 </div> | |
294 | |
295 | |
235 | 296 Looping |
237 | 297 ======= |
226 | 298 |
235 | 299 .. _`py:for`: |
226 | 300 |
235 | 301 ``py:for`` |
237 | 302 ---------- |
235 | 303 |
304 The element is repeated for every item in an iterable:: | |
226 | 305 |
306 <ul> | |
235 | 307 <li py:for="item in items">${item}</li> |
226 | 308 </ul> |
309 | |
235 | 310 Given ``items=[1, 2, 3]`` in the context data, this would produce:: |
226 | 311 |
312 <ul> | |
235 | 313 <li>1</li><li>2</li><li>3</li> |
226 | 314 </ul> |
315 | |
235 | 316 This directive can also be used as an element:: |
226 | 317 |
235 | 318 <ul> |
319 <py:for each="item in items"> | |
320 <li>${item}</li> | |
321 </py:for> | |
322 </ul> | |
323 | |
324 | |
325 Snippet Reuse | |
237 | 326 ============= |
226 | 327 |
328 .. _`py:def`: | |
329 .. _`macros`: | |
330 | |
331 ``py:def`` | |
237 | 332 ---------- |
226 | 333 |
334 The ``py:def`` directive can be used to create macros, i.e. snippets of | |
335 template code that have a name and optionally some parameters, and that can be | |
336 inserted in other places:: | |
337 | |
338 <div> | |
339 <p py:def="greeting(name)" class="greeting"> | |
340 Hello, ${name}! | |
341 </p> | |
342 ${greeting('world')} | |
343 ${greeting('everyone else')} | |
344 </div> | |
345 | |
346 The above would be rendered to:: | |
347 | |
348 <div> | |
349 <p class="greeting"> | |
350 Hello, world! | |
351 </p> | |
352 <p class="greeting"> | |
353 Hello, everyone else! | |
354 </p> | |
355 </div> | |
356 | |
394 | 357 If a macro doesn't require parameters, it can be defined without the |
358 parenthesis. For example:: | |
226 | 359 |
360 <div> | |
361 <p py:def="greeting" class="greeting"> | |
362 Hello, world! | |
363 </p> | |
394 | 364 ${greeting()} |
226 | 365 </div> |
366 | |
367 The above would be rendered to:: | |
368 | |
369 <div> | |
370 <p class="greeting"> | |
371 Hello, world! | |
372 </p> | |
373 </div> | |
374 | |
375 This directive can also be used as an element:: | |
376 | |
377 <div> | |
378 <py:def function="greeting(name)"> | |
379 <p class="greeting">Hello, ${name}!</p> | |
380 </py:def> | |
381 </div> | |
382 | |
383 | |
235 | 384 .. _Match Templates: |
226 | 385 .. _`py:match`: |
386 | |
387 ``py:match`` | |
237 | 388 ------------ |
226 | 389 |
390 This directive defines a *match template*: given an XPath expression, it | |
391 replaces any element in the template that matches the expression with its own | |
392 content. | |
393 | |
394 For example, the match template defined in the following template matches any | |
395 element with the tag name “greeting”:: | |
396 | |
397 <div> | |
398 <span py:match="greeting"> | |
399 Hello ${select('@name')} | |
400 </span> | |
401 <greeting name="Dude" /> | |
402 </div> | |
403 | |
404 This would result in the following output:: | |
405 | |
406 <div> | |
407 <span> | |
408 Hello Dude | |
409 </span> | |
410 </div> | |
411 | |
412 Inside the body of a ``py:match`` directive, the ``select(path)`` function is | |
413 made available so that parts or all of the original element can be incorporated | |
230 | 414 in the output of the match template. See [wiki:GenshiStream#UsingXPath] for |
226 | 415 more information about this function. |
416 | |
417 This directive can also be used as an element:: | |
418 | |
419 <div> | |
420 <py:match path="greeting"> | |
421 <span>Hello ${select('@name')}</span> | |
422 </py:match> | |
423 <greeting name="Dude" /> | |
424 </div> | |
425 | |
426 | |
235 | 427 Variable Binding |
237 | 428 ================ |
226 | 429 |
430 .. _`with`: | |
431 | |
432 ``py:with`` | |
237 | 433 ----------- |
226 | 434 |
435 The ``py:with`` directive lets you assign expressions to variables, which can | |
436 be used to make expressions inside the directive less verbose and more | |
437 efficient. For example, if you need use the expression ``author.posts`` more | |
438 than once, and that actually results in a database query, assigning the results | |
439 to a variable using this directive would probably help. | |
440 | |
441 For example:: | |
442 | |
443 <div> | |
444 <span py:with="y=7; z=x+10">$x $y $z</span> | |
445 </div> | |
446 | |
447 Given ``x=42`` in the context data, this would produce:: | |
448 | |
449 <div> | |
450 <span>42 7 52</span> | |
451 </div> | |
452 | |
453 This directive can also be used as an element:: | |
454 | |
455 <div> | |
456 <py:with vars="y=7; z=x+10">$x $y $z</py:with> | |
457 </div> | |
458 | |
459 Note that if a variable of the same name already existed outside of the scope | |
460 of the ``py:with`` directive, it will **not** be overwritten. Instead, it | |
461 will have the same value it had prior to the ``py:with`` assignment. | |
230 | 462 Effectively, this means that variables are immutable in Genshi. |
226 | 463 |
464 | |
235 | 465 Structure Manipulation |
237 | 466 ====================== |
235 | 467 |
468 .. _`py:attrs`: | |
469 | |
470 ``py:attrs`` | |
237 | 471 ------------ |
235 | 472 |
473 This directive adds, modifies or removes attributes from the element:: | |
474 | |
475 <ul> | |
476 <li py:attrs="foo">Bar</li> | |
477 </ul> | |
478 | |
479 Given ``foo={'class': 'collapse'}`` in the template context, this would | |
480 produce:: | |
481 | |
482 <ul> | |
483 <li class="collapse">Bar</li> | |
484 </ul> | |
485 | |
486 Attributes with the value ``None`` are omitted, so given ``foo={'class': None}`` | |
487 in the context for the same template this would produce:: | |
488 | |
489 <ul> | |
490 <li>Bar</li> | |
491 </ul> | |
492 | |
493 This directive can only be used as an attribute. | |
494 | |
495 | |
496 .. _`py:content`: | |
497 | |
498 ``py:content`` | |
237 | 499 -------------- |
235 | 500 |
501 This directive replaces any nested content with the result of evaluating the | |
502 expression:: | |
503 | |
504 <ul> | |
505 <li py:content="bar">Hello</li> | |
506 </ul> | |
507 | |
508 Given ``bar='Bye'`` in the context data, this would produce:: | |
509 | |
510 <ul> | |
511 <li>Bye</li> | |
512 </ul> | |
513 | |
514 This directive can only be used as an attribute. | |
515 | |
516 | |
517 .. _`py:replace`: | |
518 | |
519 ``py:replace`` | |
237 | 520 -------------- |
235 | 521 |
522 This directive replaces the element itself with the result of evaluating the | |
523 expression:: | |
524 | |
525 <div> | |
526 <span py:replace="bar">Hello</span> | |
527 </div> | |
528 | |
529 Given ``bar='Bye'`` in the context data, this would produce:: | |
530 | |
531 <div> | |
532 Bye | |
533 </div> | |
534 | |
535 This directive can only be used as an attribute. | |
536 | |
537 | |
538 .. _`py:strip`: | |
539 | |
540 ``py:strip`` | |
237 | 541 ------------ |
235 | 542 |
543 This directive conditionally strips the top-level element from the output. When | |
544 the value of the ``py:strip`` attribute evaluates to ``True``, the element is | |
545 stripped from the output:: | |
546 | |
547 <div> | |
548 <div py:strip="True"><b>foo</b></div> | |
549 </div> | |
550 | |
551 This would be rendered as:: | |
552 | |
553 <div> | |
554 <b>foo</b> | |
555 </div> | |
556 | |
557 As a shorthand, if the value of the ``py:strip`` attribute is empty, that has | |
558 the same effect as using a truth value (i.e. the element is stripped). | |
559 | |
560 | |
226 | 561 .. _order: |
562 | |
563 Processing Order | |
564 ================ | |
565 | |
566 It is possible to attach multiple directives to a single element, although not | |
567 all combinations make sense. When multiple directives are encountered, they are | |
568 processed in the following order: | |
569 | |
570 #. `py:def`_ | |
571 #. `py:match`_ | |
572 #. `py:when`_ | |
573 #. `py:otherwise`_ | |
574 #. `py:for`_ | |
575 #. `py:if`_ | |
576 #. `py:choose`_ | |
577 #. `py:with`_ | |
578 #. `py:replace`_ | |
579 #. `py:content`_ | |
580 #. `py:attrs`_ | |
581 #. `py:strip`_ | |
582 | |
583 | |
584 .. _includes: | |
585 | |
586 -------- | |
587 Includes | |
588 -------- | |
589 | |
590 To reuse common snippets of template code, you can include other files using | |
591 XInclude_. | |
592 | |
593 .. _xinclude: http://www.w3.org/TR/xinclude/ | |
594 | |
595 For this, you need to declare the XInclude namespace (commonly bound to the | |
596 prefix “xi”) and use the ``<xi:include>`` element where you want the external | |
597 file to be pulled in:: | |
598 | |
599 <html xmlns="http://www.w3.org/1999/xhtml" | |
230 | 600 xmlns:py="http://genshi.edgewall.org/" |
226 | 601 xmlns:xi="http://www.w3.org/2001/XInclude"> |
602 <xi:include href="base.html" /> | |
603 ... | |
604 </html> | |
605 | |
606 Include paths are relative to the filename of the template currently being | |
607 processed. So if the example above was in the file "``myapp/index.html``" | |
608 (relative to the template search path), the XInclude processor would look for | |
609 the included file at "``myapp/base.html``". You can also use Unix-style | |
610 relative paths, for example "``../base.html``" to look in the parent directory. | |
611 | |
612 Any content included this way is inserted into the generated output instead of | |
613 the ``<xi:include>`` element. The included template sees the same context data. | |
614 `Match templates`_ and `macros`_ in the included template are also available to | |
615 the including template after the point it was included. | |
616 | |
617 By default, an error will be raised if an included file is not found. If that's | |
618 not what you want, you can specify fallback content that should be used if the | |
619 include fails. For example, to to make the include above fail silently, you'd | |
273 | 620 write:: |
226 | 621 |
622 <xi:include href="base.html"><xi:fallback /></xi:include> | |
623 | |
273 | 624 See the `XInclude specification`_ for more about fallback content. Note though |
625 that Genshi currently only supports a small subset of XInclude. | |
626 | |
627 .. _`xinclude specification`: http://www.w3.org/TR/xinclude/ | |
226 | 628 |
230 | 629 Incudes in Genshi are fully dynamic: Just like normal attributes, the `href` |
226 | 630 attribute accepts expressions_, and directives_ can be used on the |
631 ``<xi:include />`` element just as on any other element, meaning you can do | |
632 things like conditional includes:: | |
633 | |
634 <xi:include href="${name}.html" py:if="not in_popup" | |
635 py:for="name in ('foo', 'bar', 'baz')" /> | |
636 | |
637 | |
638 .. _comments: | |
639 | |
640 -------- | |
641 Comments | |
642 -------- | |
643 | |
644 Normal XML/HTML comment syntax can be used in templates:: | |
645 | |
646 <!-- this is a comment --> | |
647 | |
648 However, such comments get passed through the processing pipeline and are by | |
649 default included in the final output. If that's not desired, prefix the comment | |
650 text with an exclamation mark:: | |
651 | |
652 <!-- !this is a comment too, but one that will be stripped from the output --> | |
653 | |
654 Note that it does not matter whether there's whitespace before or after the | |
655 exclamation mark, so the above could also be written as follows:: | |
656 | |
657 <!--! this is a comment too, but one that will be stripped from the output --> |