24 | | #!python |
25 | | from markup.template import Template |
26 | | |
27 | | tmpl = Template('<h1>$title</h1>') |
28 | | stream = tmpl.generate(title='Hello, world!') |
29 | | print stream.render('xhtml') |
30 | | }}} |
31 | | |
32 | | That code would produce the following output: |
33 | | |
34 | | {{{ |
35 | | #!xml |
36 | | <h1>Hello, world!</h1> |
37 | | }}} |
38 | | |
39 | | However, if you want [MarkupTemplates#Includes includes] to work, you should attain the template instance through a `TemplateLoader`, and load the template from a file: |
40 | | |
41 | | {{{ |
42 | | #!python |
43 | | from markup.template import TemplateLoader |
44 | | |
45 | | loader = TemplateLoader([templates_dir]) |
46 | | tmpl = loader.load('test.html') |
47 | | stream = tmpl.generate(title='Hello, world!') |
48 | | print stream.render('xhtml') |
49 | | }}} |
50 | | |
51 | | See the [ApiDocs API docs] of the [ApiDocs/MarkupTemplate markup.template] and [ApiDocs/MarkupCore markup.core] modules for more details. |
52 | | |
53 | | == Expressions == |
54 | | |
55 | | Python expressions can be used in text and attribute values. An expression is substituted with the result of its evaluation against the template data. Expressions need to prefixed with a dollar sign (`$`) and usually enclosed in curly braces (`{…}`). |
56 | | |
57 | | If the expression starts with a letter and contains only letters and digits, the curly braces may be omitted. In all other cases, the braces are required so that the template processors knows where the expression ends: |
58 | | |
59 | | {{{ |
60 | | >>> from markup.template import Context, Template |
61 | | >>> tmpl = Template('<em>${items[0].capitalize()} item</em>') |
62 | | >>> print tmpl.generate(Context(items=['first', 'second'])) |
63 | | <em>First item</em> |
64 | | }}} |
65 | | |
66 | | Expressions support the full power of Python. In addition, it is possible to: |
67 | | * access items in a dictionary using ''“dotted notation”'' (i.e. as if they were attributes) |
68 | | * access attributes using item access (i.e. as if they were items in a dictionary) |
69 | | |
70 | | {{{ |
71 | | >>> from markup.template import Context, Template |
72 | | >>> tmpl = Template('<em>${dict.foo}</em>') |
73 | | >>> print tmpl.generate(Context(dict={'foo': 'bar'})) |
74 | | <em>bar</em> |
75 | | }}} |
76 | | |
77 | | == Directives == |
78 | | |
79 | | ''Directives'' are elements and/or attributes in the template that are identified by the namespace `http://markup.edgewall.org/`. They can affect how the template is rendered in a number of ways: Markup provides directives for conditionals and looping, among others. |
80 | | |
81 | | To use directives in a template, the namespace should be declared, which is usually done on the root element: |
82 | | |
83 | | {{{ |
84 | | #!xml |
85 | | <html xmlns="http://www.w3.org/1999/xhtml" |
86 | | xmlns:py="http://markup.edgewall.org/" |
87 | | lang="en"> |
88 | | ... |
89 | | </html> |
90 | | }}} |
91 | | |
92 | | In this example, the default namespace is set to the XHTML namespace, and the namespace for Markup directives is bound to the prefix “py”. |
93 | | |
94 | | 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: |
95 | | |
96 | | {{{ |
97 | | #!xml |
98 | | <html xmlns="http://www.w3.org/1999/xhtml" |
99 | | xmlns:py="http://markup.edgewall.org/" |
100 | | lang="en"> |
101 | | ... |
102 | | <div py:if="foo"> |
103 | | <p>Bar</p> |
104 | | </div> |
105 | | ... |
106 | | </html> |
107 | | }}} |
108 | | |
109 | | This is basically equivalent to the following: |
110 | | |
111 | | {{{ |
112 | | #!xml |
113 | | <html xmlns="http://www.w3.org/1999/xhtml" |
114 | | xmlns:py="http://markup.edgewall.org/" |
115 | | lang="en"> |
116 | | ... |
117 | | <py:if test="foo"> |
118 | | <div> |
| 2 | #!rst |
| 3 | ============================ |
| 4 | Markup XML Template Language |
| 5 | ============================ |
| 6 | |
| 7 | Markup provides a simple XML-based template language that is heavily inspired |
| 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 |
| 18 | reference to those developing Markup templates. Templates are XML files of some |
| 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 | .. _`expressions`: |
| 31 | |
| 32 | -------------------- |
| 33 | Template Expressions |
| 34 | -------------------- |
| 35 | |
| 36 | Python_ expressions can be used in text and attribute values. An expression is |
| 37 | substituted with the result of its evaluation against the template data. |
| 38 | Expressions need to prefixed with a dollar sign (``$``) and usually enclosed in |
| 39 | curly braces (``{…}``). |
| 40 | |
| 41 | If the expression starts with a letter and contains only letters and digits, |
| 42 | the curly braces may be omitted. In all other cases, the braces are required so |
| 43 | that the template processors knows where the expression ends:: |
| 44 | |
| 45 | >>> from markup.template import Context, Template |
| 46 | >>> tmpl = Template('<em>${items[0].capitalize()} item</em>') |
| 47 | >>> print tmpl.generate(Context(items=['first', 'second'])) |
| 48 | <em>First item</em> |
| 49 | |
| 50 | Expressions support the full power of Python. In addition, it is possible to |
| 51 | access items in a dictionary using “dotted notation” (i.e. as if they were |
| 52 | attributes), and vice-versa (i.e. access attributes as if they were items in a |
| 53 | dictionary):: |
| 54 | |
| 55 | >>> from markup.template import Context, Template |
| 56 | >>> tmpl = Template('<em>${dict.foo}</em>') |
| 57 | >>> print tmpl.generate(Context(dict={'foo': 'bar'})) |
| 58 | <em>bar</em> |
| 59 | |
| 60 | |
| 61 | .. _`directives`: |
| 62 | |
| 63 | ------------------- |
| 64 | Template Directives |
| 65 | ------------------- |
| 66 | |
| 67 | Directives are elements and/or attributes in the template that are identified |
| 68 | by the namespace ``http://markup.edgewall.org/``. They can affect how the |
| 69 | template is rendered in a number of ways: Markup provides directives for |
| 70 | conditionals and looping, among others. |
| 71 | |
| 72 | To use directives in a template, the namespace should be declared, which is |
| 73 | usually done on the root element:: |
| 74 | |
| 75 | <html xmlns="http://www.w3.org/1999/xhtml" |
| 76 | xmlns:py="http://markup.edgewall.org/" |
| 77 | lang="en"> |
| 78 | ... |
| 79 | </html> |
| 80 | |
| 81 | In this example, the default namespace is set to the XHTML namespace, and the |
| 82 | namespace for Markup directives is bound to the prefix “py”. |
| 83 | |
| 84 | All directives can be applied as attributes, and some can also be used as |
| 85 | elements. The ``if`` directives for conditionals, for example, can be used in |
| 86 | both ways:: |
| 87 | |
| 88 | <html xmlns="http://www.w3.org/1999/xhtml" |
| 89 | xmlns:py="http://markup.edgewall.org/" |
| 90 | lang="en"> |
| 91 | ... |
| 92 | <div py:if="foo"> |
172 | | === `py:attrs` === |
173 | | |
174 | | This directive adds, modifies or removes attributes from the element. |
175 | | |
176 | | {{{ |
177 | | #!xml |
178 | | <ul> |
179 | | <li py:attrs="foo">Bar</li> |
180 | | </ul> |
181 | | }}} |
182 | | |
183 | | Given `foo={'class': 'collapse'}` in the template context, this would produce: |
184 | | |
185 | | {{{ |
186 | | #!xml |
187 | | <ul> |
188 | | <li class="collapse">Bar</li> |
189 | | </ul> |
190 | | }}} |
191 | | |
192 | | Attributes with the value `None` are omitted, so given `foo={'class': None}` in the context for the same template this would produce: |
193 | | |
194 | | {{{ |
195 | | #!xml |
196 | | <ul> |
197 | | <li>Bar</li> |
198 | | </ul> |
199 | | }}} |
| 212 | |
| 213 | .. _`py:def`: |
| 214 | .. _`macros`: |
| 215 | |
| 216 | ``py:def`` |
| 217 | ---------- |
| 218 | |
| 219 | The ``py:def`` directive can be used to create macros, i.e. snippets of |
| 220 | template code that have a name and optionally some parameters, and that can be |
| 221 | inserted in other places:: |
| 222 | |
| 223 | <div> |
| 224 | <p py:def="greeting(name)" class="greeting"> |
| 225 | Hello, ${name}! |
| 226 | </p> |
| 227 | ${greeting('world')} |
| 228 | ${greeting('everyone else')} |
| 229 | </div> |
| 230 | |
| 231 | The above would be rendered to:: |
| 232 | |
| 233 | <div> |
| 234 | <p class="greeting"> |
| 235 | Hello, world! |
| 236 | </p> |
| 237 | <p class="greeting"> |
| 238 | Hello, everyone else! |
| 239 | </p> |
| 240 | </div> |
| 241 | |
| 242 | If a macro doesn't require parameters, it can be defined as well as called |
| 243 | without the parenthesis. For example:: |
| 244 | |
| 245 | <div> |
| 246 | <p py:def="greeting" class="greeting"> |
| 247 | Hello, world! |
| 248 | </p> |
| 249 | ${greeting} |
| 250 | </div> |
| 251 | |
| 252 | The above would be rendered to:: |
| 253 | |
| 254 | <div> |
| 255 | <p class="greeting"> |
| 256 | Hello, world! |
| 257 | </p> |
| 258 | </div> |
| 259 | |
| 260 | This directive can also be used as an element:: |
| 261 | |
| 262 | <div> |
| 263 | <py:def function="greeting(name)"> |
| 264 | <p class="greeting">Hello, ${name}!</p> |
| 265 | </py:def> |
| 266 | </div> |
| 267 | |
| 268 | |
| 269 | .. _`py:for`: |
| 270 | |
| 271 | ``py:for`` |
| 272 | ---------- |
| 273 | |
| 274 | The element is repeated for every item in an iterable:: |
| 275 | |
| 276 | <ul> |
| 277 | <li py:for="item in items">${item}</li> |
| 278 | </ul> |
| 279 | |
| 280 | Given ``items=[1, 2, 3]`` in the context data, this would produce:: |
| 281 | |
| 282 | <ul> |
| 283 | <li>1</li><li>2</li><li>3</li> |
| 284 | </ul> |
| 285 | |
| 286 | This directive can also be used as an element:: |
| 287 | |
| 288 | <ul> |
| 289 | <py:for each="item in items"> |
| 290 | <li>${item}</li> |
| 291 | </py:for> |
| 292 | </ul> |
| 293 | |
| 294 | |
| 295 | .. _`py:if`: |
| 296 | |
| 297 | ``py:if`` |
| 298 | ------------ |
| 299 | |
| 300 | The element is only rendered if the expression evaluates to a truth value:: |
| 301 | |
| 302 | <div> |
| 303 | <b py:if="foo">${bar}</b> |
| 304 | </div> |
| 305 | |
| 306 | Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this |
| 307 | would produce:: |
| 308 | |
| 309 | <div> |
| 310 | <b>Hello</b> |
| 311 | </div> |
| 312 | |
| 313 | This directive can also be used as an element:: |
| 314 | |
| 315 | <div> |
| 316 | <py:if test="foo"> |
| 317 | <b>${bar}</b> |
| 318 | </py:if> |
| 319 | </div> |
| 320 | |
| 321 | |
| 322 | .. _`py:match`: |
| 323 | .. _Match Templates: |
| 324 | |
| 325 | ``py:match`` |
| 326 | ------------ |
| 327 | |
| 328 | This directive defines a *match template*: given an XPath expression, it |
| 329 | replaces any element in the template that matches the expression with its own |
| 330 | content. |
| 331 | |
| 332 | For example, the match template defined in the following template matches any |
| 333 | element with the tag name “greeting”:: |
| 334 | |
| 335 | <div> |
| 336 | <span py:match="greeting"> |
| 337 | Hello ${select('@name')} |
| 338 | </span> |
| 339 | <greeting name="Dude" /> |
| 340 | </div> |
| 341 | |
| 342 | This would result in the following output:: |
| 343 | |
| 344 | <div> |
| 345 | <span> |
| 346 | Hello Dude |
| 347 | </span> |
| 348 | </div> |
| 349 | |
| 350 | Inside the body of a ``py:match`` directive, the ``select(path)`` function is |
| 351 | made available so that parts or all of the original element can be incorporated |
| 352 | in the output of the match template. See [wiki:MarkupStream#UsingXPath] for |
| 353 | more information about this function. |
| 354 | |
| 355 | This directive can also be used as an element:: |
| 356 | |
| 357 | <div> |
| 358 | <py:match path="greeting"> |
| 359 | <span>Hello ${select('@name')}</span> |
| 360 | </py:match> |
| 361 | <greeting name="Dude" /> |
| 362 | </div> |
| 363 | |
| 364 | |
| 365 | .. _`py:replace`: |
| 366 | |
| 367 | ``py:replace`` |
| 368 | -------------- |
| 369 | |
| 370 | This directive replaces the element itself with the result of evaluating the |
| 371 | expression:: |
| 372 | |
| 373 | <div> |
| 374 | <span py:replace="bar">Hello</span> |
| 375 | </div> |
| 376 | |
| 377 | Given ``bar='Bye'`` in the context data, this would produce:: |
| 378 | |
| 379 | <div> |
| 380 | Bye |
| 381 | </div> |
203 | | === `py:strip` === |
204 | | |
205 | | This directive conditionally strips the top-level element from the output. When the value of the `py:strip` attribute evaluates to `True`, the element |
206 | | is stripped from the output: |
207 | | |
208 | | {{{ |
209 | | #!xml |
210 | | <div> |
211 | | <div py:strip="True"><b>foo</b></div> |
212 | | </div> |
213 | | }}} |
214 | | |
215 | | This would be rendered as: |
216 | | |
217 | | {{{ |
218 | | #!xml |
219 | | <div> |
220 | | <b>foo</b> |
221 | | </div> |
222 | | }}} |
223 | | |
224 | | 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). |
225 | | |
226 | | === `py:if` === |
227 | | |
228 | | The element is only rendered if the expression evaluates to a truth value. |
229 | | |
230 | | {{{ |
231 | | #!xml |
232 | | <div> |
233 | | <b py:if="foo">${bar}</b> |
234 | | </div> |
235 | | }}} |
236 | | |
237 | | Given the data `foo=True` and `bar='Hello'` in the template context, this would produce: |
238 | | |
239 | | {{{ |
240 | | #!xml |
241 | | <div> |
242 | | <b>Hello</b> |
243 | | </div> |
244 | | }}} |
245 | | |
246 | | This directive can also be used as an element: |
247 | | |
248 | | {{{ |
249 | | #!xml |
250 | | <div> |
251 | | <py:if test="foo"> |
252 | | <b>${bar}</b> |
253 | | </py:if> |
254 | | </div> |
255 | | }}} |
256 | | |
257 | | |
258 | | === `py:choose` / `py:when` / `py:otherwise` === |
259 | | |
260 | | This set of directives provides advanced contional processing for rendering one of several alternatives. The first matching `py:when` directive will be rendered or, if no `py:when` directive matches, the `py:otherwise` directive will be rendered. |
261 | | |
262 | | If the `py:choose` directive is empty the nested `py:when` directives will be tested for truth: |
263 | | |
264 | | {{{ |
265 | | #!xml |
266 | | <div py:choose=""> |
267 | | <span py:when="0 == 1">0</span> |
268 | | <span py:when="1 == 1">1</span> |
269 | | <span py:otherwise="">2</span> |
270 | | </div> |
271 | | }}} |
272 | | |
273 | | This would produce the following output: |
274 | | |
275 | | {{{ |
276 | | #!xml |
277 | | <div> |
278 | | <span>1</span> |
279 | | </div> |
280 | | }}} |
281 | | |
282 | | If the `py:choose` directive contains an expression the nested `py:when` directives will be tested for equality to the parent `py:choose` value: |
283 | | |
284 | | {{{ |
285 | | #!xml |
286 | | <div py:choose="1"> |
287 | | <span py:when="0">0</span> |
288 | | <span py:when="1">1</span> |
289 | | <span py:otherwise="">2</span> |
290 | | </div> |
291 | | }}} |
292 | | |
293 | | This would produce the following output: |
294 | | |
295 | | {{{ |
296 | | #!xml |
297 | | <div> |
298 | | <span>1</span> |
299 | | </div> |
300 | | }}} |
301 | | |
302 | | === `py:for` === |
303 | | |
304 | | The element is repeated for every item in an iterable: |
305 | | |
306 | | {{{ |
307 | | #!xml |
308 | | <ul> |
309 | | <li py:for="item in items">${item}</li> |
310 | | </ul> |
311 | | }}} |
312 | | |
313 | | Given `items=[1, 2, 3]` in the context data, this would produce: |
314 | | |
315 | | {{{ |
316 | | #!xml |
317 | | <ul> |
318 | | <li>1</li><li>2</li><li>3</li> |
319 | | </ul> |
320 | | }}} |
321 | | |
322 | | This directive can also be used as an element: |
323 | | |
324 | | {{{ |
325 | | #!xml |
326 | | <ul> |
327 | | <py:for each="item in items"> |
328 | | <li>${item}</li> |
329 | | </py:for> |
330 | | </ul> |
331 | | }}} |
332 | | |
333 | | === `py:def` === |
334 | | |
335 | | The `py:def` directive can be used to create ''template functions'', i.e. snippets of template code that have a name and optionally some parameters, and that can be inserted in other places. |
336 | | |
337 | | {{{ |
338 | | #!xml |
339 | | <div> |
340 | | <p py:def="greeting(name)" class="greeting"> |
341 | | Hello, ${name}! |
342 | | </p> |
343 | | ${greeting('world')} |
344 | | ${greeting('everyone else')} |
345 | | </div> |
346 | | }}} |
347 | | |
348 | | The above would be rendered to: |
349 | | |
350 | | {{{ |
351 | | #!xml |
352 | | <div> |
353 | | <p class="greeting"> |
354 | | Hello, world! |
355 | | </p> |
356 | | <p class="greeting"> |
357 | | Hello, everyone else! |
358 | | </p> |
359 | | </div> |
360 | | }}} |
361 | | |
362 | | If a template function doesn't require parameters, it can be defined as well as called without the parenthesis. For example: |
363 | | |
364 | | {{{ |
365 | | #!xml |
366 | | <div> |
367 | | <p py:def="greeting" class="greeting"> |
368 | | Hello, world! |
369 | | </p> |
370 | | ${greeting} |
371 | | </div> |
372 | | }}} |
373 | | |
374 | | The above would be rendered to: |
375 | | |
376 | | {{{ |
377 | | #!xml |
378 | | <div> |
379 | | <p class="greeting"> |
380 | | Hello, world! |
381 | | </p> |
382 | | </div> |
383 | | }}} |
384 | | |
385 | | This directive can also be used as an element: |
386 | | |
387 | | {{{ |
388 | | #!xml |
389 | | <div> |
390 | | <py:def function="greeting(name)"> |
391 | | <p class="greeting">Hello, ${name}!</p> |
392 | | </py:def> |
393 | | </div> |
394 | | }}} |
395 | | |
396 | | === `py:with` === |
397 | | |
398 | | 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. |
399 | | |
400 | | For example: |
401 | | |
402 | | {{{ |
403 | | #!xml |
404 | | <div> |
405 | | <span py:with="y=7; z=x+10">$x $y $z</span> |
406 | | </div> |
407 | | }}} |
408 | | |
409 | | Given `x=42` in the context data, this would produce: |
410 | | |
411 | | {{{ |
412 | | #!xml |
413 | | <div> |
414 | | <span>42 7 52</span> |
415 | | </div> |
416 | | }}} |
417 | | |
418 | | This directive can also be used as an element: |
419 | | |
420 | | {{{ |
421 | | #!xml |
422 | | <div> |
423 | | <py:with vars="y=7; z=x+10">$x $y $z</py:with> |
424 | | </div> |
425 | | }}} |
426 | | |
427 | | 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 Markup. |
428 | | |
429 | | === `py:match` === |
430 | | |
431 | | 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. |
432 | | |
433 | | For example, the match template defined in the following template matches any element with the tag name “greeting”: |
434 | | |
435 | | {{{ |
436 | | #!xml |
437 | | <div> |
438 | | <span py:match="greeting"> |
439 | | Hello ${select('@name')} |
440 | | </span> |
441 | | <greeting name="Dude" /> |
442 | | </div> |
443 | | }}} |
444 | | |
445 | | This would result in the following output: |
446 | | |
447 | | {{{ |
448 | | #!xml |
449 | | <div> |
450 | | <span> |
451 | | Hello Dude |
452 | | </span> |
453 | | </div> |
454 | | }}} |
455 | | |
456 | | 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 [wiki:MarkupStream#UsingXPath] for more information about this function. |
457 | | |
458 | | This directive can also be used as an element: |
459 | | |
460 | | {{{ |
461 | | #!xml |
462 | | <div> |
463 | | <py:match path="greeting"> |
464 | | <span>Hello ${select('@name')}</span> |
465 | | </py:match> |
466 | | <greeting name="Dude" /> |
467 | | </div> |
468 | | }}} |
469 | | |
470 | | == Processing order == |
471 | | |
472 | | Directives are evaluated in the following order: |
473 | | |
474 | | * [MarkupTemplates#py:def py:def] |
475 | | * [MarkupTemplates#py:match py:match] |
476 | | * [MarkupTemplates#py:when py:when] |
477 | | * [MarkupTemplates#py:otherwise py:otherwise] |
478 | | * [MarkupTemplates#py:for py:for] |
479 | | * [MarkupTemplates#py:if py:if] |
480 | | * [MarkupTemplates#py:choose py:choose] |
481 | | * [MarkupTemplates#py:with py:with] |
482 | | * [MarkupTemplates#py:replace py:replace] |
483 | | * [MarkupTemplates#py:content py:content] |
484 | | * [MarkupTemplates#py:attrs py:attrs] |
485 | | * [MarkupTemplates#py:strip py:strip] |
486 | | |
487 | | == Includes == |
488 | | |
489 | | To reuse common snippets of template code, you can include other files using [http://www.w3.org/TR/xinclude/ XInclude]. |
490 | | |
491 | | 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: |
492 | | |
493 | | {{{ |
494 | | #!xml |
495 | | <html xmlns="http://www.w3.org/1999/xhtml" |
496 | | xmlns:py="http://markup.edgewall.org/" |
497 | | xmlns:xi="http://www.w3.org/2001/XInclude"> |
498 | | <xi:include href="base.html" /> |
499 | | ... |
500 | | </html> |
501 | | }}} |
502 | | |
503 | | 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. |
504 | | |
505 | | 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. [wiki:MarkupTemplates#py:match Match templates] and [wiki:MarkupTemplates#py:def template functions] in the included template are also available to the including template after the point it was included. |
506 | | |
507 | | 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: |
508 | | |
509 | | {{{ |
510 | | #!xml |
| 385 | |
| 386 | .. _`py:strip`: |
| 387 | |
| 388 | ``py:strip`` |
| 389 | ------------ |
| 390 | |
| 391 | This directive conditionally strips the top-level element from the output. When |
| 392 | the value of the ``py:strip`` attribute evaluates to ``True``, the element is |
| 393 | stripped from the output:: |
| 394 | |
| 395 | <div> |
| 396 | <div py:strip="True"><b>foo</b></div> |
| 397 | </div> |
| 398 | |
| 399 | This would be rendered as:: |
| 400 | |
| 401 | <div> |
| 402 | <b>foo</b> |
| 403 | </div> |
| 404 | |
| 405 | As a shorthand, if the value of the ``py:strip`` attribute is empty, that has |
| 406 | the same effect as using a truth value (i.e. the element is stripped). |
| 407 | |
| 408 | |
| 409 | .. _`with`: |
| 410 | |
| 411 | ``py:with`` |
| 412 | ----------- |
| 413 | |
| 414 | The ``py:with`` directive lets you assign expressions to variables, which can |
| 415 | be used to make expressions inside the directive less verbose and more |
| 416 | efficient. For example, if you need use the expression ``author.posts`` more |
| 417 | than once, and that actually results in a database query, assigning the results |
| 418 | to a variable using this directive would probably help. |
| 419 | |
| 420 | For example:: |
| 421 | |
| 422 | <div> |
| 423 | <span py:with="y=7; z=x+10">$x $y $z</span> |
| 424 | </div> |
| 425 | |
| 426 | Given ``x=42`` in the context data, this would produce:: |
| 427 | |
| 428 | <div> |
| 429 | <span>42 7 52</span> |
| 430 | </div> |
| 431 | |
| 432 | This directive can also be used as an element:: |
| 433 | |
| 434 | <div> |
| 435 | <py:with vars="y=7; z=x+10">$x $y $z</py:with> |
| 436 | </div> |
| 437 | |
| 438 | Note that if a variable of the same name already existed outside of the scope |
| 439 | of the ``py:with`` directive, it will **not** be overwritten. Instead, it |
| 440 | will have the same value it had prior to the ``py:with`` assignment. |
| 441 | Effectively, this means that variables are immutable in Markup. |
| 442 | |
| 443 | |
| 444 | .. _order: |
| 445 | |
| 446 | Processing Order |
| 447 | ================ |
| 448 | |
| 449 | It is possible to attach multiple directives to a single element, although not |
| 450 | all combinations make sense. When multiple directives are encountered, they are |
| 451 | processed in the following order: |
| 452 | |
| 453 | #. `py:def`_ |
| 454 | #. `py:match`_ |
| 455 | #. `py:when`_ |
| 456 | #. `py:otherwise`_ |
| 457 | #. `py:for`_ |
| 458 | #. `py:if`_ |
| 459 | #. `py:choose`_ |
| 460 | #. `py:with`_ |
| 461 | #. `py:replace`_ |
| 462 | #. `py:content`_ |
| 463 | #. `py:attrs`_ |
| 464 | #. `py:strip`_ |
| 465 | |
| 466 | |
| 467 | .. _includes: |
| 468 | |
| 469 | -------- |
| 470 | Includes |
| 471 | -------- |
| 472 | |
| 473 | To reuse common snippets of template code, you can include other files using |
| 474 | XInclude_. |
| 475 | |
| 476 | .. _xinclude: http://www.w3.org/TR/xinclude/ |
| 477 | |
| 478 | For this, you need to declare the XInclude namespace (commonly bound to the |
| 479 | prefix “xi”) and use the ``<xi:include>`` element where you want the external |
| 480 | file to be pulled in:: |
| 481 | |
| 482 | <html xmlns="http://www.w3.org/1999/xhtml" |
| 483 | xmlns:py="http://markup.edgewall.org/" |
| 484 | xmlns:xi="http://www.w3.org/2001/XInclude"> |
| 485 | <xi:include href="base.html" /> |
| 486 | ... |
| 487 | </html> |
| 488 | |
| 489 | Include paths are relative to the filename of the template currently being |
| 490 | processed. So if the example above was in the file "``myapp/index.html``" |
| 491 | (relative to the template search path), the XInclude processor would look for |
| 492 | the included file at "``myapp/base.html``". You can also use Unix-style |
| 493 | relative paths, for example "``../base.html``" to look in the parent directory. |
| 494 | |
| 495 | Any content included this way is inserted into the generated output instead of |
| 496 | the ``<xi:include>`` element. The included template sees the same context data. |
| 497 | `Match templates`_ and `macros`_ in the included template are also available to |
| 498 | the including template after the point it was included. |
| 499 | |
| 500 | By default, an error will be raised if an included file is not found. If that's |
| 501 | not what you want, you can specify fallback content that should be used if the |
| 502 | include fails. For example, to to make the include above fail silently, you'd |
| 503 | write: |
| 504 | |