comparison doc/templates.txt @ 442:97544725bb7f trunk

Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
author cmlenz
date Thu, 12 Apr 2007 22:40:49 +0000
parents
children ec7890aa7c0b
comparison
equal deleted inserted replaced
441:2755b06148b3 442:97544725bb7f
1 .. -*- mode: rst; encoding: utf-8 -*-
2
3 ========================
4 Genshi Templating Basics
5 ========================
6
7 Genshi provides a template engine that can be used for generating either
8 markup (such as HTML_ or XML_) or plain text. While both share some of the
9 syntax (and much of the underlying implementation) they are essentially
10 separate languages.
11
12 .. _html: http://www.w3.org/html/
13 .. _xml: http://www.w3.org/XML/
14
15 This document describes the common parts of the template engine and will be most
16 useful as reference to those developing Genshi templates. Templates are XML or
17 plain text files that include processing directives_ that affect how the
18 template is rendered, and template expressions_ that are dynamically substituted
19 by variable data.
20
21
22 .. contents:: Contents
23 :depth: 3
24 .. sectnum::
25
26 --------
27 Synopsis
28 --------
29
30 A Genshi *markup template* is a well-formed XML document with embedded Python
31 used for control flow and variable substitution. Markup templates should be
32 used to generate any kind of HTML or XML output, as they provide many advantages
33 over simple text-based templates (such as automatic escaping of strings).
34
35 The following illustrates a very basic Genshi markup template::
36
37 <?python
38 title = "A Genshi Template"
39 fruits = ["apple", "orange", "kiwi"]
40 ?>
41 <html xmlns:py="http://genshi.edgewall.org/">
42 <head>
43 <title py:content="title">This is replaced.</title>
44 </head>
45
46 <body>
47 <p>These are some of my favorite fruits:</p>
48 <ul>
49 <li py:for="fruit in fruits">
50 I like ${fruit}s
51 </li>
52 </ul>
53 </body>
54 </html>
55
56 This example shows:
57
58 (a) a Python code block, using a processing instruction
59 (b) the Genshi namespace declaration
60 (c) usage of templates directives (``py:content`` and ``py:for``)
61 (d) an inline Python expression (``${fruit}``).
62
63 A *text template* is a simple plain text document that can also contain embedded
64 Python code. Text templates can be used to generate simple *non-markup* text
65 formats, such as the body of an plain text email. For example::
66
67 Dear $name,
68
69 These are some of my favorite fruits:
70 #for fruit in fruits
71 * $fruit
72 #end
73
74
75 ----------
76 Python API
77 ----------
78
79 The Python code required for templating with Genshi is generally based on the
80 following pattern:
81
82 * Attain a ``MarkupTemplate`` or ``TextTemplate`` object from a string or
83 file-like object containing the template source. This can either be done
84 directly, or through a ``TemplateLoader`` instance.
85 * Call the ``generate()`` method of the template, passing any data that should
86 be made available to the template as keyword arguments.
87 * Serialize the resulting stream using its ``render()`` method.
88
89 For example::
90
91 >>> from genshi.template import MarkupTemplate
92 >>> tmpl = MarkupTemplate('<h1>Hello, $name!</h1>')
93 >>> stream = tmpl.generate(name='world')
94 >>> print stream.render()
95 <h1>Hello, world!</h1>
96
97 Using a text template is similar::
98
99 >>> from genshi.template import TextTemplate
100 >>> tmpl = TextTemplate('Hello, $name!')
101 >>> stream = tmpl.generate(name='world')
102 >>> print stream.render()
103 Hello, world!
104
105 .. note:: See the Serialization_ section of the `Markup Streams`_ page for
106 information on configuring template output options.
107
108 .. _serialization: streams.html#serialization
109 .. _`Markup Streams`: streams.html
110
111 Using a template loader provides the advantage that “compiled” templates are
112 automatically cached, and only parsed again when the template file changes. In
113 addition, it enables the use of a *template search path*, allowing template
114 directories to be spread across different file-system locations. Using a
115 template loader would generally look as follows::
116
117 from genshi.template import TemplateLoader
118 loader = TemplateLoader([templates_dir1, templates_dir2])
119 tmpl = loader.load('test.html')
120 stream = tmpl.generate(title='Hello, world!')
121 print stream.render()
122
123 See the `API documentation <api/index.html>`_ for details on using Genshi via
124 the Python API.
125
126
127 .. _`expressions`:
128
129 ------------------------------------
130 Template Expressions and Code Blocks
131 ------------------------------------
132
133 Python_ expressions can be used in text and directive arguments. An expression
134 is substituted with the result of its evaluation against the template data.
135 Expressions in text (which includes the values of non-directive attributes) need
136 to prefixed with a dollar sign (``$``) and usually enclosed in curly braces
137 (``{…}``).
138
139 .. _python: http://www.python.org/
140
141 If the expression starts with a letter and contains only letters, digits, dots,
142 and underscores, the curly braces may be omitted. In all other cases, the
143 braces are required so that the template processor knows where the expression
144 ends::
145
146 >>> from genshi.template import MarkupTemplate
147 >>> tmpl = MarkupTemplate('<em>${items[0].capitalize()} item</em>')
148 >>> print tmpl.generate(items=['first', 'second'])
149 <em>First item</em>
150
151 Expressions support the full power of Python. In addition, it is possible to
152 access items in a dictionary using “dotted notation” (i.e. as if they were
153 attributes), and vice-versa (i.e. access attributes as if they were items in a
154 dictionary)::
155
156 >>> from genshi.template import MarkupTemplate
157 >>> tmpl = MarkupTemplate('<em>${dict.foo}</em>')
158 >>> print tmpl.generate(dict={'foo': 'bar'})
159 <em>bar</em>
160
161 Because there are two ways to access either attributes or items, expressions
162 do not raise the standard ``AttributeError`` or ``IndexError`` exceptions, but
163 rather an exception of the type ``UndefinedError``. The same kind of error is
164 raised when you try to access a top-level variable that is not in the context
165 data.
166
167
168 .. _`code blocks`:
169
170 Code Blocks
171 ===========
172
173 XML templates also support full Python code blocks using the ``<?python ?>``
174 processing instruction::
175
176 <div>
177 <?python
178 from genshi.builder import tag
179 def greeting(name):
180 return tag.b('Hello, %s!' % name') ?>
181 ${greeting('world')}
182 </div>
183
184 This will produce the following output::
185
186 <div>
187 <b>Hello, world!</b>
188 </div>
189
190 Code blocks can import modules, define classes and functions, and basically do
191 anything you can do in normal Python code. What code blocks can *not* do is to
192 produce content that is included directly in the generated page.
193
194 .. note:: Using the ``print`` statement will print to the standard output
195 stream, just as it does for other Python code in your application.
196
197 This feature is not supposed to encourage mixing application code into
198 templates, which is generally considered bad design. If you're using many code
199 blocks, that me be a sign that you should move such code into separate Python
200 modules.
201
202 .. note:: Code blocks are not currently supported in text templates.
203
204
205 .. _`error handling`:
206
207 Error Handling
208 ==============
209
210 By default, Genshi allows you to access variables that are not defined, without
211 raising a ``NameError`` exception as regular Python code would::
212
213 >>> from genshi.template import MarkupTemplate
214 >>> tmpl = MarkupTemplate('<p>${doh}</p>')
215 >>> print tmpl.generate().render('xhtml')
216 <p></p>
217
218 You *will* however get an exception if you try to call an undefined variable, or
219 do anything else with it, such as accessing its attributes::
220
221 >>> from genshi.template import MarkupTemplate
222 >>> tmpl = MarkupTemplate('<p>${doh.oops}</p>')
223 >>> print tmpl.generate().render('xhtml')
224 Traceback (most recent call last):
225 ...
226 UndefinedError: "doh" not defined
227
228 If you need to know whether a variable is defined, you can check its type
229 against the ``Undefined`` class, for example in a conditional directive::
230
231 >>> from genshi.template import MarkupTemplate
232 >>> tmpl = MarkupTemplate('<p>${type(doh) is not Undefined}</p>')
233 >>> print tmpl.generate().render('xhtml')
234 <p>False</p>
235
236 Alternatively, the built-in functions defined_ or value_of_ can be used in this
237 case.
238
239 Strict Mode
240 -----------
241
242 In addition to the default "lenient" error handling, Genshi lets you use a less
243 forgiving mode if you prefer errors blowing up loudly instead of being ignored
244 silently.
245
246 This mode can be chosen by passing the ``lookup='strict'`` keyword argument to
247 the template initializer, or by passing the ``variable_lookup='strict'`` keyword
248 argument to the ``TemplateLoader`` initializer::
249
250 >>> from genshi.template import MarkupTemplate
251 >>> tmpl = MarkupTemplate('<p>${doh}</p>', lookup='strict')
252 >>> print tmpl.generate().render('xhtml')
253 Traceback (most recent call last):
254 ...
255 UndefinedError: "doh" not defined
256
257 When using strict mode, any reference to an undefined variable, as well as
258 trying to access an non-existing item or attribute of an object, will cause an
259 ``UndefinedError`` to be raised immediately.
260
261 .. note:: While this mode is currently not the default, it may be promoted to
262 the default in future versions of Genshi. In general, the default
263 lenient error handling mode can be considered dangerous as it silently
264 ignores typos.
265
266 Custom Modes
267 ------------
268
269 In addition to the built-in "lenient" and "strict" modes, it is also possible to
270 use a custom error handling mode. For example, you could use lenient error
271 handling in a production environment, while also logging a warning when an
272 undefined variable is referenced.
273
274 See the API documentation of the ``genshi.template.eval`` module for details.
275
276
277 Built-in Functions & Types
278 ==========================
279
280 The following functions and types are available by default in template code, in
281 addition to the standard built-ins that are available to all Python code.
282
283 .. _`defined`:
284
285 ``defined(name)``
286 -----------------
287 This function determines whether a variable of the specified name exists in
288 the context data, and returns ``True`` if it does.
289
290 .. _`value_of`:
291
292 ``value_of(name, default=None)``
293 --------------------------------
294 This function returns the value of the variable with the specified name if
295 such a variable is defined, and returns the value of the ``default``
296 parameter if no such variable is defined.
297
298 .. _`Markup`:
299
300 ``Markup(text)``
301 ----------------
302 The ``Markup`` type marks a given string as being safe for inclusion in markup,
303 meaning it will *not* be escaped in the serialization stage. Use this with care,
304 as not escaping a user-provided string may allow malicious users to open your
305 web site to cross-site scripting attacks.
306
307 .. _`Undefined`:
308
309 ``Undefined``
310 ----------------
311 The ``Undefined`` type can be used to check whether a reference variable is
312 defined, as explained in `error handling`_.
313
314
315 .. _`directives`:
316
317 -------------------
318 Template Directives
319 -------------------
320
321 Directives provide control flow functionality for templates, such as conditions
322 or iteration. As the syntax for directives depends on whether you're using
323 markup or text templates, refer to the
324 `XML Template Language <xml-templates.html>`_ or
325 `Text Template Language <text-templates.html>`_ pages for information.
Copyright (C) 2012-2017 Edgewall Software