Imported Upstream version 12.1.0
[contrib/python-twisted.git] / doc / web / howto / twisted-templates.html
1 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE html  PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
2   <head>
3 <title>Twisted Documentation: HTML Templating with twisted.web.template</title>
4 <link href="stylesheet.css" rel="stylesheet" type="text/css"/>
5   </head>
6
7   <body bgcolor="white">
8     <h1 class="title">HTML Templating with twisted.web.template</h1>
9     <div class="toc"><ol><li><a href="#auto0">A Very Quick Introduction To Templating In Python</a></li><li><a href="#auto1">twisted.web.template - Why And How you Might Want to Use It</a></li><ul><li><a href="#auto2">Template Attributes</a></li><li><a href="#auto3">Slots</a></li><li><a href="#auto4">Iteration</a></li><li><a href="#auto5">Sub-views</a></li><li><a href="#auto6">Transparent</a></li></ul><li><a href="#auto7">Quoting</a></li><li><a href="#auto8">Deferreds</a></li><li><a href="#auto9">A Brief Note on Formats and DOCTYPEs</a></li><li><a href="#auto10">A Bit of History</a></li></ol></div>
10     <div class="content">
11 <span/>
12 <h2>A Very Quick Introduction To Templating In Python<a name="auto0"/></h2>
13 <p>
14 HTML templating is the process of transforming a template document (one which
15 describes style and structure, but does not itself include any content) into
16 some HTML output which includes information about objects in your application.
17 There are many, many libraries for doing this in Python: to name a few, <a href="http://jinja.pocoo.org/" shape="rect">jinja2</a>, <a href="http://docs.djangoproject.com/en/dev/ref/templates/" shape="rect">django templates</a>,
18 and <a href="http://www.clearsilver.net/" shape="rect">clearsilver</a>.  You can easily use
19 any of these libraries in your Twisted Web application, either by running them
20 as <a href="web-in-60/wsgi.html" shape="rect">WSGI applications</a> or by calling your
21 preferred templating system's APIs to produce their output as strings, and then
22 writing those strings to <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.request.Request.write.html" title="twisted.web.request.Request.write">Request.write</a></code>.
23 </p>
24 <p>Before we begin explaining how to use it, I'd like to stress that you
25 don't <i>need</i> to use Twisted's templating system if you prefer some other
26 way to generate HTML.  Use it if it suits your personal style or your
27 application, but feel free to use other things.  Twisted includes templating for
28 its own use, because the <code>twisted.web</code> server needs to produce HTML
29 in various places, and we didn't want to add another large dependency for that.
30 Twisted is <em>not</em> in any way incompatible with other systems, so that has
31 nothing to do with the fact that we use our own.</p>
32 <p>
33 </p>
34 <h2>twisted.web.template - Why And How you Might Want to Use It<a name="auto1"/></h2>
35 <p>
36 Twisted includes a templating system, <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.html" title="twisted.web.template">twisted.web.template</a></code>.  This can be convenient for Twisted
37 applications that want to produce some basic HTML for a web interface without an
38 additional dependency.
39 </p>
40 <p>
41 <code>twisted.web.template</code> also includes
42 support for <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>s, so
43 you can incrementally render the output of a page based on the results of <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>s that your application
44 has returned.  This feature is fairly unique among templating libraries.
45 </p>
46 <p>
47 In <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.html" title="twisted.web.template">twisted.web.template</a></code>, templates are XHTML files
48 which also contain a special namespace for indicating dynamic portions of the
49 document. For example:
50 </p>
51 <div class="html-listing"><pre class="htmlsource">
52 &lt;html xmlns:t=&quot;http://twistedmatrix.com/ns/twisted.web.template/0.1&quot;&gt;
53 &lt;body&gt;
54   &lt;div t:render=&quot;header&quot; /&gt;
55   &lt;div id=&quot;content&quot;&gt;
56     &lt;p&gt;Content goes here.&lt;/p&gt;
57   &lt;/div&gt;
58   &lt;div t:render=&quot;footer&quot; /&gt;
59 &lt;/body&gt;
60 &lt;/html&gt;
61 </pre><div class="caption">template example - <a href="listings/template-1.xml"><span class="filename">listings/template-1.xml</span></a></div></div>
62 The basic unit of templating is <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.Element.html" title="twisted.web.template.Element">twisted.web.template.Element</a></code>. An Element is given a way of
63 loading a bit of markup like the above example, and knows how to
64 correlate <code>render</code> attributes within that markup to Python methods
65 exposed with <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.renderer.html" title="twisted.web.template.renderer">twisted.web.template.renderer</a></code>:
66 <div class="py-listing"><pre><p class="py-linenumber"> 1
67  2
68  3
69  4
70  5
71  6
72  7
73  8
74  9
75 10
76 11
77 12
78 13
79 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Element</span>, <span class="py-src-variable">renderer</span>, <span class="py-src-variable">XMLFile</span>
80 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">filepath</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePath</span>
81
82 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ExampleElement</span>(<span class="py-src-parameter">Element</span>):
83     <span class="py-src-variable">loader</span> = <span class="py-src-variable">XMLFile</span>(<span class="py-src-variable">FilePath</span>(<span class="py-src-string">'template-1.xml'</span>))
84
85     @<span class="py-src-variable">renderer</span>
86     <span class="py-src-keyword">def</span> <span class="py-src-identifier">header</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
87         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-string">'Header.'</span>)
88
89     @<span class="py-src-variable">renderer</span>
90     <span class="py-src-keyword">def</span> <span class="py-src-identifier">footer</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
91         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-string">'Footer.'</span>)
92 </pre><div class="caption">element example - <a href="listings/element_1.py"><span class="filename">listings/element_1.py</span></a></div></div>
93 In order to combine the two, we must render the element.  For this simple
94 example, we can use the <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.flattenString.html" title="twisted.web.template.flattenString">flattenString</a></code> API, which will convert a
95 single template object - such as an <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.Element.html" title="twisted.web.template.Element">Element</a></code> - into a <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code> which fires with a single string,
96 the HTML output of the rendering process.
97 <div class="py-listing"><pre><p class="py-linenumber">1
98 2
99 3
100 4
101 5
102 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">flattenString</span>
103 <span class="py-src-keyword">from</span> <span class="py-src-variable">element_1</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ExampleElement</span>
104 <span class="py-src-keyword">def</span> <span class="py-src-identifier">renderDone</span>(<span class="py-src-parameter">output</span>):
105     <span class="py-src-keyword">print</span> <span class="py-src-variable">output</span>
106 <span class="py-src-variable">flattenString</span>(<span class="py-src-variable">None</span>, <span class="py-src-variable">ExampleElement</span>()).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">renderDone</span>)
107 </pre><div class="caption">rendering snippet - <a href="listings/render_1.py"><span class="filename">listings/render_1.py</span></a></div></div>
108 <p>This short program cheats a little bit; we know that there are no <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>s in the template which
109 require the reactor to eventually fire; therefore, we can simply add a callback
110 which outputs the result.  Also, none of the <code>renderer</code> functions
111 require the <code>request</code> object, so it's acceptable to
112 pass <code>None</code> through here.  (The 'request' object here is used only to
113 relay information about the rendering process to each renderer, so you may
114 always use whatever object makes sense for your application.  Note, however,
115 that renderers from library code may require an <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.iweb.IRequest.html" title="twisted.web.iweb.IRequest">IRequest</a></code>.)</p>
116 <p>
117 If you run it yourself, you can see that it produces the following output:
118 </p>
119 <div class="html-listing"><pre class="htmlsource">
120 &lt;html&gt;
121 &lt;body&gt;
122   &lt;div&gt;Header.&lt;/div&gt;
123   &lt;div id=&quot;content&quot;&gt;
124     &lt;p&gt;Content goes here.&lt;/p&gt;
125   &lt;/div&gt;
126   &lt;div&gt;Footer.&lt;/div&gt;
127 &lt;/body&gt;
128 &lt;/html&gt;
129 </pre><div class="caption">rendering output 1 - <a href="listings/output-1.html"><span class="filename">listings/output-1.html</span></a></div></div>
130 The third parameter to a renderer method is a <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.Tag.html" title="twisted.web.template.Tag">Tag</a></code> object which represents the XML element
131 with the <code>t:render</code> attribute in the template. Calling a <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.Tag.html" title="twisted.web.template.Tag">Tag</a></code> adds children to the element
132 in the DOM, which may be strings, more <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.Tag.html" title="twisted.web.template.Tag">Tag</a></code>s, or other renderables such as <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.Element.html" title="twisted.web.template.Element">Element</a></code>s.
133 For example, to make the header and footer bold:
134 <div class="py-listing"><pre><p class="py-linenumber"> 1
135  2
136  3
137  4
138  5
139  6
140  7
141  8
142  9
143 10
144 11
145 12
146 13
147 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Element</span>, <span class="py-src-variable">renderer</span>, <span class="py-src-variable">XMLFile</span>, <span class="py-src-variable">tags</span>
148 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">filepath</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePath</span>
149
150 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ExampleElement</span>(<span class="py-src-parameter">Element</span>):
151     <span class="py-src-variable">loader</span> = <span class="py-src-variable">XMLFile</span>(<span class="py-src-variable">FilePath</span>(<span class="py-src-string">'template-1.xml'</span>))
152
153     @<span class="py-src-variable">renderer</span>
154     <span class="py-src-keyword">def</span> <span class="py-src-identifier">header</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
155         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-variable">tags</span>.<span class="py-src-variable">b</span>(<span class="py-src-string">'Header.'</span>))
156
157     @<span class="py-src-variable">renderer</span>
158     <span class="py-src-keyword">def</span> <span class="py-src-identifier">footer</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
159         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-variable">tags</span>.<span class="py-src-variable">b</span>(<span class="py-src-string">'Footer.'</span>))
160 </pre><div class="caption">tag manipulation example - <a href="listings/element_2.py"><span class="filename">listings/element_2.py</span></a></div></div>
161
162 Rendering this in a similar way to the first example would produce:
163
164 <div class="html-listing"><pre class="htmlsource">
165 &lt;html&gt;
166 &lt;body&gt;
167   &lt;div&gt;&lt;b&gt;Header.&lt;/b&gt;&lt;/div&gt;
168   &lt;div id=&quot;content&quot;&gt;
169     &lt;p&gt;Content goes here.&lt;/p&gt;
170   &lt;/div&gt;
171   &lt;div&gt;&lt;b&gt;Footer.&lt;/b&gt;&lt;/div&gt;
172 &lt;/body&gt;
173 &lt;/html&gt;
174 </pre><div class="caption">tag manipulation output - <a href="listings/output-2.html"><span class="filename">listings/output-2.html</span></a></div></div>
175
176 In addition to adding children, call syntax can be used to set attributes on a
177 tag. For example, to change the <code>id</code> on the <code>div</code> while
178 adding children:
179
180 <div class="py-listing"><pre><p class="py-linenumber"> 1
181  2
182  3
183  4
184  5
185  6
186  7
187  8
188  9
189 10
190 11
191 12
192 13
193 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Element</span>, <span class="py-src-variable">renderer</span>, <span class="py-src-variable">XMLFile</span>, <span class="py-src-variable">tags</span>
194 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">filepath</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePath</span>
195
196 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ExampleElement</span>(<span class="py-src-parameter">Element</span>):
197     <span class="py-src-variable">loader</span> = <span class="py-src-variable">XMLFile</span>(<span class="py-src-variable">FilePath</span>(<span class="py-src-string">'template-1.xml'</span>))
198
199     @<span class="py-src-variable">renderer</span>
200     <span class="py-src-keyword">def</span> <span class="py-src-identifier">header</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
201         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-variable">tags</span>.<span class="py-src-variable">p</span>(<span class="py-src-string">'Header.'</span>), <span class="py-src-variable">id</span>=<span class="py-src-string">'header'</span>)
202
203     @<span class="py-src-variable">renderer</span>
204     <span class="py-src-keyword">def</span> <span class="py-src-identifier">footer</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
205         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-variable">tags</span>.<span class="py-src-variable">p</span>(<span class="py-src-string">'Footer.'</span>), <span class="py-src-variable">id</span>=<span class="py-src-string">'footer'</span>)
206 </pre><div class="caption">attributes example - <a href="listings/element_3.py"><span class="filename">listings/element_3.py</span></a></div></div>
207
208 And this would produce the following page:
209
210 <div class="html-listing"><pre class="htmlsource">
211 &lt;html&gt;
212 &lt;body&gt;
213   &lt;div id=&quot;header&quot;&gt;&lt;p&gt;Header.&lt;/p&gt;&lt;/div&gt;
214   &lt;div id=&quot;content&quot;&gt;
215     &lt;p&gt;Content goes here.&lt;/p&gt;
216   &lt;/div&gt;
217   &lt;div id=&quot;footer&quot;&gt;&lt;p&gt;Footer.&lt;/p&gt;&lt;/div&gt;
218 &lt;/body&gt;
219 &lt;/html&gt;
220 </pre><div class="caption">attributes output - <a href="listings/output-3.html"><span class="filename">listings/output-3.html</span></a></div></div>
221
222 <p>
223 Calling a tag mutates it, it and returns the tag itself, so you can pass it
224 forward and call it multiple times if you have multiple children or attributes
225 to add to it. <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.html" title="twisted.web.template">twisted.web.template</a></code> also exposes some
226 convenient objects for building more complex markup structures from within
227 renderer methods in the <code>tags</code> object.  In the examples above, we've
228 only used <code>tags.p</code> and <code>tags.b</code>, but there should be a <code>tags.x</code> for each <em>x</em> which is a valid HTML tag.  There may be
229 some omissions, but if you find one, please feel free to file a bug.
230 </p>
231
232 <h3>Template Attributes<a name="auto2"/></h3>
233
234 <code>t:attr</code> tags allow you to set HTML attributes
235 (like <code>href</code> in an <code>&lt;a href=&quot;...</code>) on an enclosing
236 element.
237
238 <h3>Slots<a name="auto3"/></h3>
239
240 <code>t:slot</code> tags allow you to specify &quot;slots&quot; which you can
241 conveniently fill with multiple pieces of data straight from your Python
242 program.
243
244 The following example demonstrates both <code>t:attr</code>
245 and <code>t:slot</code> in action. Here we have a layout which displays a person's
246 profile on your snazzy new Twisted-powered social networking site. We use
247 the <code>t:attr</code> tag to drop in the &quot;src&quot; attribute on the profile picture,
248 where the actual value of src attribute gets specified by a <code>t:slot</code>
249 tag <em>within</em> the <code>t:attr</code> tag. Confused? It should make more
250 sense when you see the code:
251
252 <div class="html-listing"><pre class="htmlsource">
253 &lt;div xmlns:t=&quot;http://twistedmatrix.com/ns/twisted.web.template/0.1&quot;
254     t:render=&quot;person_profile&quot;
255     class=&quot;profile&quot;&gt;
256 &lt;img&gt;&lt;t:attr name=&quot;src&quot;&gt;&lt;t:slot name=&quot;profile_image_url&quot; /&gt;&lt;/t:attr&gt;&lt;/img&gt; 
257 &lt;p&gt;&lt;t:slot name=&quot;person_name&quot; /&gt;&lt;/p&gt;
258 &lt;/div&gt;
259 </pre><div class="caption">slots and attributes template - <a href="listings/slots-attributes-1.xml"><span class="filename">listings/slots-attributes-1.xml</span></a></div></div>
260
261 <div class="py-listing"><pre><p class="py-linenumber"> 1
262  2
263  3
264  4
265  5
266  6
267  7
268  8
269  9
270 10
271 11
272 12
273 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Element</span>, <span class="py-src-variable">renderer</span>, <span class="py-src-variable">XMLFile</span>
274 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">filepath</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePath</span>
275
276 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ExampleElement</span>(<span class="py-src-parameter">Element</span>):
277     <span class="py-src-variable">loader</span> = <span class="py-src-variable">XMLFile</span>(<span class="py-src-variable">FilePath</span>(<span class="py-src-string">'slots-attributes-1.xml'</span>))
278
279     @<span class="py-src-variable">renderer</span>
280     <span class="py-src-keyword">def</span> <span class="py-src-identifier">person_profile</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
281         <span class="py-src-comment"># Note how convenient it is to pass these attributes in!</span>
282         <span class="py-src-variable">tag</span>.<span class="py-src-variable">fillSlots</span>(<span class="py-src-variable">person_name</span>=<span class="py-src-string">'Luke'</span>,
283                       <span class="py-src-variable">profile_image_url</span>=<span class="py-src-string">'http://example.com/user.png'</span>)
284         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>
285 </pre><div class="caption">slots and attributes element - <a href="listings/slots_attributes_1.py"><span class="filename">listings/slots_attributes_1.py</span></a></div></div>
286 <div class="html-listing"><pre class="htmlsource">
287 &lt;div class=&quot;profile&quot;&gt;
288 &lt;img src=&quot;http://example.com/user.png&quot; /&gt; 
289 &lt;p&gt;Luke&lt;/p&gt;
290 &lt;/div&gt;
291 </pre><div class="caption">slots and attributes output - <a href="listings/slots-attributes-output.html"><span class="filename">listings/slots-attributes-output.html</span></a></div></div>
292
293 <h3>Iteration<a name="auto4"/></h3>
294
295 <p>Often, you will have a sequence of things, and want to render each of them,
296 repeating a part of the template for each one. This can be done by
297 cloning <code>tag</code> in your renderer:</p>
298
299 <div class="html-listing"><pre class="htmlsource">
300 &lt;ul xmlns:t=&quot;http://twistedmatrix.com/ns/twisted.web.template/0.1&quot;&gt;
301     &lt;li t:render=&quot;widgets&quot;&gt;&lt;t:slot name=&quot;widgetName&quot;/&gt;&lt;/li&gt;
302 &lt;/ul&gt;
303 </pre><div class="caption">iteration template - <a href="listings/iteration-1.xml"><span class="filename">listings/iteration-1.xml</span></a></div></div>
304 <div class="py-listing"><pre><p class="py-linenumber"> 1
305  2
306  3
307  4
308  5
309  6
310  7
311  8
312  9
313 10
314 11
315 12
316 13
317 14
318 15
319 16
320 17
321 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Element</span>, <span class="py-src-variable">renderer</span>, <span class="py-src-variable">XMLFile</span>, <span class="py-src-variable">flattenString</span>
322 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">filepath</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePath</span>
323
324 <span class="py-src-keyword">class</span> <span class="py-src-identifier">WidgetsElement</span>(<span class="py-src-parameter">Element</span>):
325     <span class="py-src-variable">loader</span> = <span class="py-src-variable">XMLFile</span>(<span class="py-src-variable">FilePath</span>(<span class="py-src-string">'iteration-1.xml'</span>))
326
327     <span class="py-src-variable">widgetData</span> = [<span class="py-src-string">'gadget'</span>, <span class="py-src-string">'contraption'</span>, <span class="py-src-string">'gizmo'</span>, <span class="py-src-string">'doohickey'</span>]
328
329     @<span class="py-src-variable">renderer</span>
330     <span class="py-src-keyword">def</span> <span class="py-src-identifier">widgets</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
331         <span class="py-src-keyword">for</span> <span class="py-src-variable">widget</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">widgetData</span>:
332             <span class="py-src-keyword">yield</span> <span class="py-src-variable">tag</span>.<span class="py-src-variable">clone</span>().<span class="py-src-variable">fillSlots</span>(<span class="py-src-variable">widgetName</span>=<span class="py-src-variable">widget</span>)
333
334 <span class="py-src-keyword">def</span> <span class="py-src-identifier">printResult</span>(<span class="py-src-parameter">result</span>):
335     <span class="py-src-keyword">print</span> <span class="py-src-variable">result</span>
336
337 <span class="py-src-variable">flattenString</span>(<span class="py-src-variable">None</span>, <span class="py-src-variable">WidgetsElement</span>()).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">printResult</span>)
338 </pre><div class="caption">iteration element - <a href="listings/iteration-1.py"><span class="filename">listings/iteration-1.py</span></a></div></div>
339 <div class="html-listing"><pre class="htmlsource">
340 &lt;ul&gt;
341     &lt;li&gt;gadget&lt;/li&gt;&lt;li&gt;contraption&lt;/li&gt;&lt;li&gt;gizmo&lt;/li&gt;&lt;li&gt;doohickey&lt;/li&gt;
342 &lt;/ul&gt;
343 </pre><div class="caption">iteration output - <a href="listings/iteration-output-1.xml"><span class="filename">listings/iteration-output-1.xml</span></a></div></div>
344
345 <p>This renderer works because a renderer can return anything that can be
346 rendered, not just <code>tag</code>. In this case, we define a generator, which
347 returns a thing that is iterable. We also could have returned
348 a <code>list</code>. Anything that is iterable will be rendered by <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.html" title="twisted.web.template">twisted.web.template</a></code> rendering each item in it. In
349 this case, each item is a copy of the tag the renderer received, each filled
350 with the name of a widget.</p>
351
352 <h3>Sub-views<a name="auto5"/></h3>
353
354 <p>Another common pattern is to delegate the rendering logic for a small part of
355 the page to a separate <code>Element</code>.  For example, the widgets from the
356 iteration example above might be more complicated to render.  You can define
357 an <code>Element</code> subclass which can render a single widget.  The renderer
358 method on the container can then yield instances of this
359 new <code>Element</code> subclass.</p>
360
361 <div class="py-listing"><pre><p class="py-linenumber">1
362 2
363 3
364 </p>&lt;<span class="py-src-variable">ul</span> <span class="py-src-variable">xmlns</span>:<span class="py-src-variable">t</span>=<span class="py-src-string">&quot;http://twistedmatrix.com/ns/twisted.web.template/0.1&quot;</span>&gt;
365     &lt;<span class="py-src-variable">li</span> <span class="py-src-variable">t</span>:<span class="py-src-variable">render</span>=<span class="py-src-string">&quot;widgets&quot;</span>&gt;&lt;<span class="py-src-variable">span</span> <span class="py-src-variable">t</span>:<span class="py-src-variable">render</span>=<span class="py-src-string">&quot;name&quot;</span> /&gt;&lt;/<span class="py-src-variable">li</span>&gt;
366 &lt;/<span class="py-src-variable">ul</span>&gt;
367 </pre><div class="caption">subview template - <a href="listings/subviews-1.xml"><span class="filename">listings/subviews-1.xml</span></a></div></div>
368 <div class="py-listing"><pre><p class="py-linenumber"> 1
369  2
370  3
371  4
372  5
373  6
374  7
375  8
376  9
377 10
378 11
379 12
380 13
381 14
382 15
383 16
384 17
385 18
386 19
387 20
388 21
389 22
390 23
391 24
392 25
393 26
394 27
395 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> (
396     <span class="py-src-variable">XMLFile</span>, <span class="py-src-variable">TagLoader</span>, <span class="py-src-variable">Element</span>, <span class="py-src-variable">renderer</span>, <span class="py-src-variable">flattenString</span>)
397 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">filepath</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePath</span>
398
399 <span class="py-src-keyword">class</span> <span class="py-src-identifier">WidgetsElement</span>(<span class="py-src-parameter">Element</span>):
400     <span class="py-src-variable">loader</span> = <span class="py-src-variable">XMLFile</span>(<span class="py-src-variable">FilePath</span>(<span class="py-src-string">'subviews-1.xml'</span>))
401
402     <span class="py-src-variable">widgetData</span> = [<span class="py-src-string">'gadget'</span>, <span class="py-src-string">'contraption'</span>, <span class="py-src-string">'gizmo'</span>, <span class="py-src-string">'doohickey'</span>]
403
404     @<span class="py-src-variable">renderer</span>
405     <span class="py-src-keyword">def</span> <span class="py-src-identifier">widgets</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
406         <span class="py-src-keyword">for</span> <span class="py-src-variable">widget</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">widgetData</span>:
407             <span class="py-src-keyword">yield</span> <span class="py-src-variable">WidgetElement</span>(<span class="py-src-variable">TagLoader</span>(<span class="py-src-variable">tag</span>), <span class="py-src-variable">widget</span>)
408
409 <span class="py-src-keyword">class</span> <span class="py-src-identifier">WidgetElement</span>(<span class="py-src-parameter">Element</span>):
410     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">loader</span>, <span class="py-src-parameter">name</span>):
411         <span class="py-src-variable">Element</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>, <span class="py-src-variable">loader</span>)
412         <span class="py-src-variable">self</span>.<span class="py-src-variable">_name</span> = <span class="py-src-variable">name</span>
413
414     @<span class="py-src-variable">renderer</span>
415     <span class="py-src-keyword">def</span> <span class="py-src-identifier">name</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
416         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_name</span>)
417
418 <span class="py-src-keyword">def</span> <span class="py-src-identifier">printResult</span>(<span class="py-src-parameter">result</span>):
419     <span class="py-src-keyword">print</span> <span class="py-src-variable">result</span>
420
421 <span class="py-src-variable">flattenString</span>(<span class="py-src-variable">None</span>, <span class="py-src-variable">WidgetsElement</span>()).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">printResult</span>)
422 </pre><div class="caption">subview element - <a href="listings/subviews-1.py"><span class="filename">listings/subviews-1.py</span></a></div></div>
423 <div class="html-listing"><pre class="htmlsource">
424 &lt;ul&gt;
425       &lt;li&gt;&lt;span&gt;gadget&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;contraption&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;gizmo&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;doohickey&lt;/span&gt;&lt;/li&gt;
426 &lt;/ul&gt;
427 </pre><div class="caption">subview output - <a href="listings/subviews-output-1.xml"><span class="filename">listings/subviews-output-1.xml</span></a></div></div>
428
429 <p><code>TagLoader</code> lets the portion of the overall template related to
430 widgets be re-used for <code>WidgetElement</code>, which is otherwise a
431 normal <code>Element</code> subclass not much different
432 from <code>WidgetsElement</code>.  Notice that the <em>name</em> renderer on
433 the <code>span</code> tag in this template is satisfied
434 from <code>WidgetElement</code>, not <code>WidgetsElement</code>.</p>
435
436 <h3>Transparent<a name="auto6"/></h3>
437
438 Note how renderers, slots and attributes require you to specify a renderer on
439 some outer HTML element. What if you don't want to be forced to add an element
440 to your DOM just to drop some content into it? Maybe it messes with your
441 layout, and you can't get it to work in IE with that extra <code>div</code>
442 tag? Perhaps you need <code>t:transparent</code>, which allows you to drop some
443 content in without any surrounding &quot;container&quot; tag. For example:
444
445 <div class="html-listing"><pre class="htmlsource">
446 &lt;div xmlns:t=&quot;http://twistedmatrix.com/ns/twisted.web.template/0.1&quot;&gt;
447 &lt;!-- layout decision - these things need to be *siblings* --&gt;
448 &lt;t:transparent t:render=&quot;renderer1&quot; /&gt;
449 &lt;t:transparent t:render=&quot;renderer2&quot; /&gt;
450 &lt;/div&gt;
451
452 </pre><div class="caption">transparent template - <a href="listings/transparent-1.xml"><span class="filename">listings/transparent-1.xml</span></a></div></div>
453
454 <div class="py-listing"><pre><p class="py-linenumber"> 1
455  2
456  3
457  4
458  5
459  6
460  7
461  8
462  9
463 10
464 11
465 12
466 13
467 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Element</span>, <span class="py-src-variable">renderer</span>, <span class="py-src-variable">XMLFile</span>
468 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">filepath</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePath</span>
469
470 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ExampleElement</span>(<span class="py-src-parameter">Element</span>):
471     <span class="py-src-variable">loader</span> = <span class="py-src-variable">XMLFile</span>(<span class="py-src-variable">FilePath</span>(<span class="py-src-string">'transparent-1.xml'</span>))
472
473     @<span class="py-src-variable">renderer</span>
474     <span class="py-src-keyword">def</span> <span class="py-src-identifier">renderer1</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
475         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-string">&quot;hello&quot;</span>)
476
477     @<span class="py-src-variable">renderer</span>
478     <span class="py-src-keyword">def</span> <span class="py-src-identifier">renderer2</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
479         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-string">&quot;world&quot;</span>)
480 </pre><div class="caption">transparent element - <a href="listings/transparent_element.py"><span class="filename">listings/transparent_element.py</span></a></div></div>
481
482 <div class="html-listing"><pre class="htmlsource">
483 &lt;div&gt;
484 &lt;!-- layout decision - these things need to be *siblings* --&gt;
485 hello
486 world
487 &lt;/div&gt;
488 </pre><div class="caption">transparent rendering output - <a href="listings/transparent-output.html"><span class="filename">listings/transparent-output.html</span></a></div></div>
489
490 <h2>Quoting<a name="auto7"/></h2>
491
492 <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.html" title="twisted.web.template">twisted.web.template</a></code> will quote any strings that place
493 into the DOM.  This provides protection against <a href="http://en.wikipedia.org/wiki/Cross-site_scripting" shape="rect">XSS attacks</a>, in
494 addition to just generally making it easy to put arbitrary strings onto a web
495 page, without worrying about what they might have in them.  This can easily be
496 demonstrated with an element using the same template from our earlier examples.
497 Here's an element that returns some &quot;special&quot; characters in HTML ('&lt;', '&gt;',
498 and '&quot;', which is special in attribute values):
499
500 <div class="py-listing"><pre><p class="py-linenumber"> 1
501  2
502  3
503  4
504  5
505  6
506  7
507  8
508  9
509 10
510 11
511 12
512 13
513 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Element</span>, <span class="py-src-variable">renderer</span>, <span class="py-src-variable">XMLFile</span>
514 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">filepath</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">FilePath</span>
515
516 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ExampleElement</span>(<span class="py-src-parameter">Element</span>):
517     <span class="py-src-variable">loader</span> = <span class="py-src-variable">XMLFile</span>(<span class="py-src-variable">FilePath</span>(<span class="py-src-string">'template-1.xml'</span>))
518
519     @<span class="py-src-variable">renderer</span>
520     <span class="py-src-keyword">def</span> <span class="py-src-identifier">header</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
521         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-string">'&lt;&lt;&lt;Header&gt;&gt;&gt;!'</span>)
522
523     @<span class="py-src-variable">renderer</span>
524     <span class="py-src-keyword">def</span> <span class="py-src-identifier">footer</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
525         <span class="py-src-keyword">return</span> <span class="py-src-variable">tag</span>(<span class="py-src-string">'&gt;&gt;&gt;&quot;Footer!&quot;&lt;&lt;&lt;'</span>, <span class="py-src-variable">id</span>=<span class="py-src-string">'&lt;&quot;fun&quot;&gt;'</span>)
526 </pre><div class="caption">renderers returning &quot;special&quot; characters - <a href="listings/quoting_element.py"><span class="filename">listings/quoting_element.py</span></a></div></div>
527
528 Note that they are all safely quoted in the output, and will appear in a web
529 browser just as you returned them from your Python method:
530
531 <div class="html-listing"><pre class="htmlsource">
532 &lt;html&gt;
533 &lt;body&gt;
534   &lt;div&gt;&amp;lt;&amp;lt;&amp;lt;Header&amp;gt;&amp;gt;&amp;gt;!&lt;/div&gt;
535   &lt;div id=&quot;content&quot;&gt;
536     &lt;p&gt;Content goes here.&lt;/p&gt;
537   &lt;/div&gt;
538   &lt;div id=&quot;&amp;lt;&amp;quot;fun&amp;quot;&amp;gt;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&quot;Footer!&quot;&amp;lt;&amp;lt;&amp;lt;&lt;/div&gt;
539 &lt;/body&gt;
540 &lt;/html&gt;
541 </pre><div class="caption">output containing &quot;special&quot; characters - <a href="listings/quoting-output.html"><span class="filename">listings/quoting-output.html</span></a></div></div>
542
543 <h2>Deferreds<a name="auto8"/></h2>
544
545 Finally, a simple demonstration of Deferred support, the unique feature of <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.html" title="twisted.web.template">twisted.web.template</a></code>.  Simply put, any renderer may
546 return a Deferred which fires with some template content instead of the template
547 content itself.  As shown above, <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.flattenString.html" title="twisted.web.template.flattenString">flattenString</a></code> will return a Deferred that
548 fires with the full content of the string.  But if there's a lot of content, you
549 might not want to wait before starting to send some of it to your HTTP client:
550 for that case, you can use <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.flatten.html" title="twisted.web.template.flatten">flatten</a></code>.
551 It's difficult to demonstrate this directly in a browser-based application;
552 unless you insert very long delays before firing your Deferreds, it just looks
553 like your browser is instantly displaying everything.  Here's an example that
554 just prints out some HTML template, with markers inserted for where certain
555 events happen:
556
557 <div class="py-listing"><pre><p class="py-linenumber"> 1
558  2
559  3
560  4
561  5
562  6
563  7
564  8
565  9
566 10
567 11
568 12
569 13
570 14
571 15
572 16
573 17
574 18
575 19
576 20
577 21
578 22
579 23
580 24
581 25
582 26
583 27
584 28
585 29
586 30
587 31
588 32
589 </p><span class="py-src-keyword">import</span> <span class="py-src-variable">sys</span>
590 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">template</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">XMLString</span>, <span class="py-src-variable">Element</span>, <span class="py-src-variable">renderer</span>, <span class="py-src-variable">flatten</span>
591 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">defer</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Deferred</span>
592
593 <span class="py-src-variable">sample</span> = <span class="py-src-variable">XMLString</span>(
594     <span class="py-src-string">&quot;&quot;&quot;
595     &lt;div xmlns:t=&quot;http://twistedmatrix.com/ns/twisted.web.template/0.1&quot;&gt;
596     Before waiting ...
597     &lt;span t:render=&quot;wait&quot;&gt;&lt;/span&gt;
598     ... after waiting.
599     &lt;/div&gt;
600     &quot;&quot;&quot;</span>)
601
602 <span class="py-src-keyword">class</span> <span class="py-src-identifier">WaitForIt</span>(<span class="py-src-parameter">Element</span>):
603     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>):
604         <span class="py-src-variable">Element</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>, <span class="py-src-variable">loader</span>=<span class="py-src-variable">sample</span>)
605         <span class="py-src-variable">self</span>.<span class="py-src-variable">deferred</span> = <span class="py-src-variable">Deferred</span>()
606
607     @<span class="py-src-variable">renderer</span>
608     <span class="py-src-keyword">def</span> <span class="py-src-identifier">wait</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>, <span class="py-src-parameter">tag</span>):
609         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">deferred</span>.<span class="py-src-variable">addCallback</span>(
610             <span class="py-src-keyword">lambda</span> <span class="py-src-variable">aValue</span>: <span class="py-src-variable">tag</span>(<span class="py-src-string">&quot;A value: &quot;</span> + <span class="py-src-variable">repr</span>(<span class="py-src-variable">aValue</span>)))
611
612 <span class="py-src-keyword">def</span> <span class="py-src-identifier">done</span>(<span class="py-src-parameter">ignore</span>):
613     <span class="py-src-keyword">print</span>(<span class="py-src-string">&quot;[[[Deferred fired.]]]&quot;</span>)
614
615 <span class="py-src-keyword">print</span>(<span class="py-src-string">'[[[Rendering the template.]]]'</span>)
616 <span class="py-src-variable">it</span> = <span class="py-src-variable">WaitForIt</span>()
617 <span class="py-src-variable">flatten</span>(<span class="py-src-variable">None</span>, <span class="py-src-variable">it</span>, <span class="py-src-variable">sys</span>.<span class="py-src-variable">stdout</span>.<span class="py-src-variable">write</span>).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">done</span>)
618 <span class="py-src-keyword">print</span>(<span class="py-src-string">'[[[In progress... now firing the Deferred.]]]'</span>)
619 <span class="py-src-variable">it</span>.<span class="py-src-variable">deferred</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">&quot;&lt;value&gt;&quot;</span>)
620 <span class="py-src-keyword">print</span>(<span class="py-src-string">'[[[All done.]]]'</span>)
621 </pre><div class="caption">deferred example - <a href="listings/wait_for_it.py"><span class="filename">listings/wait_for_it.py</span></a></div></div>
622
623 If you run this example, you should get the following output:
624
625 <div class="html-listing"><pre class="htmlsource">
626 [[[Rendering the template.]]]
627 &lt;div&gt;
628     Before waiting ...
629     [[[In progress... now firing the Deferred.]]]
630 &lt;span&gt;A value: '&amp;lt;value&amp;gt;'&lt;/span&gt;
631     ... after waiting.
632     &lt;/div&gt;[[[Deferred fired.]]]
633 [[[All done.]]]
634 </pre><div class="caption">output from deferred example - <a href="listings/waited-for-it.html"><span class="filename">listings/waited-for-it.html</span></a></div></div>
635
636 This demonstrates that part of the output (everything up to
637 &quot;<code>[[[In progress...</code>&quot;) is written out immediately as it's rendered.
638 But once it hits the Deferred, <code>WaitForIt</code>'s rendering needs to pause
639 until <code>.callback(...)</code> is called on that Deferred.  You can see that
640 no further output is produced until the message indicating that the Deferred is
641 being fired is complete.  By returning Deferreds and using <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.web.template.flatten.html" title="twisted.web.template.flatten">flatten</a></code>, you can avoid buffering large
642 amounts of data.
643
644 <h2>A Brief Note on Formats and DOCTYPEs<a name="auto9"/></h2>
645
646 <p>
647 The goal of <code>twisted.web.template</code> is to emit both valid <a href="http://whatwg.org/html" shape="rect">HTML</a> or <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-xhtml-syntax.html#the-xhtml-syntax" shape="rect">XHTML</a>.
648 However, in order to get the maximally standards-compliant output format you
649 desire, you have to know which one you want, and take a few simple steps to emit
650 it correctly.  Many browsers will probably work with most output if you ignore
651 this section entirely, but <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#the-doctype" shape="rect">the
652     HTML specification recommends that you specify an appropriate DOCTYPE</a>.
653 </p>
654
655 <p>
656 As a <code>DOCTYPE</code> declaration in your template would describe the
657 template itself, rather than its output, it won't be included in your output.
658 If you wish to annotate your template output with a DOCTYPE, you will have to
659 write it to the browser out of band.  One way to do this would be to simply
660 do <code>request.write('&lt;!DOCTYPE html&gt;\n')</code> when you are ready to
661 begin emitting your response.  The same goes for an XML <code>DOCTYPE</code>
662 declaration.
663 </p>
664
665 <p>
666 <code>twisted.web.template</code> will remove the <code>xmlns</code> attributes
667 used to declare
668 the <code>http://twistedmatrix.com/ns/twisted.web.template/0.1</code> namespace,
669 but it will not modify other namespace declaration attributes.  Therefore if you
670 wish to serialize in HTML format, you should not use other namespaces; if you
671 wish to serialize to XML, feel free to insert any namespace declarations that
672 are appropriate, and they will appear in your output.
673 </p>
674
675 <div class="note"><strong>Note: </strong>
676 This relaxed approach is correct in many cases.  However, in certain contexts -
677 especially &lt;script&gt; and &lt;style&gt; tags - quoting rules differ in
678 significant ways between HTML and XML, and between different browsers' parsers
679 in HTML.  If you want to generate dynamic content inside a script or stylesheet,
680 the best option is to load the resource externally so you don't have to worry
681 about quoting rules.  The second best option is to strictly configure your
682 content-types and DOCTYPE declarations for XML, whose quoting rules are simple
683 and compatible with the approach that <code>twisted.web.template</code> takes.
684 And, please remember: regardless of how you put it there, any user input placed
685 inside a &lt;script&gt; or &lt;style&gt; tag is a potential security issue.
686 </div>
687
688 <h2>A Bit of History<a name="auto10"/></h2>
689 <p>
690 Those of you who used Divmod Nevow may notice some
691 similarities.  <code>twisted.web.template</code> is in fact derived from the
692 latest version of Nevow, but includes only the latest components from Nevow's
693 rendering pipeline, and does not have any of the legacy compatibility layers
694 that Nevow grew over time.  This should make
695 using <code>twisted.web.template</code> a similar experience for many long-time
696 users of Twisted who have previously used Nevow for its twisted-friendly
697 templating, but more straightforward for new users.
698 </p>
699 </div>
700
701     <p><a href="index.html">Index</a></p>
702     <span class="version">Version: 12.1.0</span>
703   </body>
704 </html>