1 | Nevow XML Templates |
---|
2 | =================== |
---|
3 |
|
---|
4 | Stan syntax is cool, but eventually you are going to want to integrate your |
---|
5 | Python code with a template designed by an HTML monkey. Nevow accomplishes this |
---|
6 | by providing an xmlfile loader which uses the built-in Python SAX libraries to |
---|
7 | generate a tree of stan behind the scenes. The general rule is anything that is |
---|
8 | possible in stan should be possible in a pure XML template; of course, the XML |
---|
9 | syntax is generally going to be much more verbose. |
---|
10 |
|
---|
11 | * `loaders.xmlfile`_ |
---|
12 | * `Nevow's xmlns declaration`_ |
---|
13 | * `Nevow's Tag Attribute Language`_ |
---|
14 | * `nevow:render`_ |
---|
15 | * `Built-in renderers`_ |
---|
16 | * `nevow:data`_ |
---|
17 | * `nevow:pattern`_ |
---|
18 | * `nevow:slot`_ |
---|
19 | * `nevow:attr`_ |
---|
20 | * `nevow:invisible`_ |
---|
21 | * `xmlstr, htmlfile, and htmlstr`_ |
---|
22 |
|
---|
23 | loaders.xmlfile |
---|
24 | --------------- |
---|
25 |
|
---|
26 | Wherever you have seen a loaders.stan being created in any of the example code, |
---|
27 | a loaders.xmlfile can be substituted instead. At the most basic, xmlfile merely |
---|
28 | requires the name of an xml template:: |
---|
29 |
|
---|
30 | class HelloXML(rend.Page): |
---|
31 | docFactory = loaders.xmlfile('hello.xml') |
---|
32 |
|
---|
33 | Placing the following xml in the hello.xml file will cause HelloXML to display a |
---|
34 | static page when it is rendered:: |
---|
35 |
|
---|
36 | <html>Hello, world!</html> |
---|
37 |
|
---|
38 | The following additional keyword arguments may be given to xmlfile to configure |
---|
39 | it: |
---|
40 |
|
---|
41 | templateDirectory |
---|
42 | The path to the directory which contains the template file. Defaults to ''. |
---|
43 |
|
---|
44 | ignoreDocType |
---|
45 | If True, discard any DOCTYPE declaration when building the DOM from this |
---|
46 | template. When false, preserve the DOCTYPE, causing it to show up in the final |
---|
47 | output. Useful for when you are inserting an XML fragment into a larger page |
---|
48 | and do not wish to generate invalid XML as output. Defaults to False. |
---|
49 |
|
---|
50 | ignoreComment |
---|
51 | If True, discard XML comments, causing them to disappear from the output. If |
---|
52 | False, preserve comments and render them in the final output unchanged. |
---|
53 | Defaults to False. |
---|
54 |
|
---|
55 | pattern |
---|
56 | If present, the given pattern name will be looked up and used as the root of |
---|
57 | the template. If not present, the entire document will be used as the |
---|
58 | template. Useful for embedding fragments of an XML document in a larger page. |
---|
59 | Defaults to None. |
---|
60 |
|
---|
61 | Nevow's xmlns declaration |
---|
62 | ------------------------- |
---|
63 |
|
---|
64 | In order for Nevow to notice and process any XML directives in the template |
---|
65 | file, you must declare the Nevow xmlns at the top of your XML document. Nevow's |
---|
66 | xmlns is:: |
---|
67 |
|
---|
68 | http://nevow.com/ns/nevow/0.1 |
---|
69 |
|
---|
70 | The syntax for declaring that your xml document uses this namespace is:: |
---|
71 |
|
---|
72 | <html xmlns:nevow="http://nevow.com/ns/nevow/0.1"></html> |
---|
73 |
|
---|
74 | You may replace the text "nevow" in the above example with any name you choose. |
---|
75 | For example, many people use "n" because it is shorter to type. If you do so, be |
---|
76 | sure to replace all occurrences of the nevow namespace in the examples with the |
---|
77 | namespace name you choose. |
---|
78 |
|
---|
79 | Nevow's Tag Attribute Language |
---|
80 | ------------------------------ |
---|
81 |
|
---|
82 | The markup you will add to your XHTML file in order to invoke Nevow code |
---|
83 | consists mostly of namespaced tag attributes. This approach was influenced |
---|
84 | heavily by the Zope Page Templates (ZPT) Tag Attribute Language (TAL). However, |
---|
85 | I felt that TAL did not go far enough in removing control flow and branching |
---|
86 | possibilities from the XML template. Nevow's main philosophy is that it should |
---|
87 | be as easy as possible to move from the XML document into Python code, and that |
---|
88 | the Python code should have ultimate control over manipulating the structure of |
---|
89 | the XML template. |
---|
90 |
|
---|
91 | The key is that it is easy to expose Python methods that you write to your XML |
---|
92 | template, and it is easy for the XML templates to mark nodes which it wishes the |
---|
93 | Python method to manipulate. In this way, if either the Python implementation |
---|
94 | changes or the location or content of the marked nodes change in the XML |
---|
95 | template, the other side will be isolated from these changes. |
---|
96 |
|
---|
97 | Nevow's XML templating has two attributes which invoke Python code: |
---|
98 |
|
---|
99 | * nevow:render -- Invokes a Python method and replaces the template node with the result |
---|
100 | * nevow:data -- Invokes a Python method and sets the data special for the node to the result |
---|
101 |
|
---|
102 | It has one attribute which marks nodes as manipulatable by Python code: |
---|
103 |
|
---|
104 | * nevow:pattern -- Gives a node a name so that Python code may clone and mutate copies of this node |
---|
105 |
|
---|
106 | It also has two namespaced tags: |
---|
107 |
|
---|
108 | * nevow:slot -- Works in the same way as the slot attribute |
---|
109 | * nevow:attr -- Indicates that an attribute of the parent tag should be manipulated by Python code in some way |
---|
110 |
|
---|
111 | nevow:render |
---|
112 | ------------ |
---|
113 |
|
---|
114 | When the nevow:render attribute is encountered, the xmlfile loader sets the |
---|
115 | render special to a directive constructed with the attribute value. When the |
---|
116 | template is rendered, this means that the appropriate render_* method will be |
---|
117 | looked up on the IRendererFactory (generally the Page instance):: |
---|
118 |
|
---|
119 | <html><div nevow:render="foo" /></html> |
---|
120 |
|
---|
121 | With the render_foo method:: |
---|
122 |
|
---|
123 | def render_foo(self, ctx, data): |
---|
124 | return "Hello" |
---|
125 |
|
---|
126 | Will result in the document:: |
---|
127 |
|
---|
128 | <html>Hello</html> |
---|
129 |
|
---|
130 | Note that the return value of the render method replaces the template node in |
---|
131 | the DOM, so if you want the template node to remain, you should use ctx.tag. |
---|
132 |
|
---|
133 | Built-in renderers |
---|
134 | ------------------ |
---|
135 |
|
---|
136 | Nevow comes with various built in renderers on the Page class. |
---|
137 |
|
---|
138 | data |
---|
139 | Renders the current data as-is inside the current node. |
---|
140 |
|
---|
141 | string |
---|
142 | Renders the current data as a string inside the current node. |
---|
143 |
|
---|
144 | sequence |
---|
145 | Iterates the current data, copying the "item" pattern for each item. Sets the |
---|
146 | the data special of the new node to the item, and inserts the result in the |
---|
147 | current node. See the nevow.rend.sequence docstring for information about |
---|
148 | other used patterns, including "header", "divider", "footer" and "empty". |
---|
149 |
|
---|
150 | mapping |
---|
151 | Calls .items() on the current data, and calls ctx.fillSlots(key, value) for |
---|
152 | every key, value pair in the result. Returns the template tag. |
---|
153 |
|
---|
154 | xml |
---|
155 | Inserts the current data into the template after wrapping it in an xml |
---|
156 | instance. Not very useful in practice. |
---|
157 |
|
---|
158 | nevow:data |
---|
159 | ---------- |
---|
160 |
|
---|
161 | When the nevow:data attribute is encountered, the xmlfile loader sets the data |
---|
162 | special of the current node to a directive constructed with the attribute value. |
---|
163 | When the template is rendered, this means that the appropriate data_* method |
---|
164 | will be looked up on the current IContainer (generally the Page instance). The |
---|
165 | data_* method will be called, and the result will be set as the data special of |
---|
166 | the current Tag:: |
---|
167 |
|
---|
168 | <html><div nevow:data="name" nevow:render="data" /></html> |
---|
169 |
|
---|
170 | With the data_name method:: |
---|
171 |
|
---|
172 | def data_name(self, ctx, data): |
---|
173 | return "Hello!" |
---|
174 |
|
---|
175 | Will result in the document:: |
---|
176 |
|
---|
177 | <html><div>Hello!</div></html> |
---|
178 |
|
---|
179 | Note that with a data attribute on a node but no renderer, the result of the |
---|
180 | data method will be set as the data special for that tag, and child render |
---|
181 | methods will be passed this data. |
---|
182 |
|
---|
183 | nevow:pattern |
---|
184 | ------------- |
---|
185 |
|
---|
186 | When the nevow:pattern attribute is encountered, the xmlfile loader sets the |
---|
187 | pattern special of the current node to the attribute value as a string. |
---|
188 | Renderers which are above this node may then make copies of it using the |
---|
189 | nevow.inevow.IQ of the current context. With the template:: |
---|
190 |
|
---|
191 | <html nevow:render="stuff"><div nevow:pattern="somePattern" nevow:render="data" /></html> |
---|
192 |
|
---|
193 | And the renderer:: |
---|
194 |
|
---|
195 | def render_stuff(self, ctx, data): |
---|
196 | pat = inevow.IQ(ctx).patternGenerator('somePattern') |
---|
197 | return [pat(data=1), pat(data=2)] |
---|
198 |
|
---|
199 | Will result in the document:: |
---|
200 |
|
---|
201 | <html><div>1</div><div>2</div></html> |
---|
202 |
|
---|
203 | nevow:slot |
---|
204 | ---------- |
---|
205 |
|
---|
206 | When the nevow:slot tag is encountered, the xmlfile loader constructs a |
---|
207 | nevow.stan.slot instance, passing the name attribute value as the slot name. The |
---|
208 | children of the slot node are added as children of the new slot instance. This |
---|
209 | is useful if you wish to put patterns inside the slot. With the template:: |
---|
210 |
|
---|
211 | <html nevow:render="stuff"><nevow:slot name="slotName" /></html> |
---|
212 |
|
---|
213 | And the render method:: |
---|
214 |
|
---|
215 | def render_stuff(self, ctx, data): |
---|
216 | ctx.fillSlots('slotName', "Hello.") |
---|
217 | return ctx.tag |
---|
218 |
|
---|
219 | This document will be produced:: |
---|
220 |
|
---|
221 | <html>Hello.</html> |
---|
222 |
|
---|
223 | nevow:attr |
---|
224 | ---------- |
---|
225 |
|
---|
226 | When the nevow:attr tag is encountered, the contents of the nevow:attr node will |
---|
227 | be assigned to the attribute of the parent tag with the name of the value of the |
---|
228 | name attribute. Perhaps an example will be a little clearer:: |
---|
229 |
|
---|
230 | <html><a><nevow:attr name="href">HELLO!</nevow:attr>Goodbye</a></html> |
---|
231 |
|
---|
232 | This document will be produced:: |
---|
233 |
|
---|
234 | <html><a href="HELLO!">Goodbye</a></html> |
---|
235 |
|
---|
236 | While this syntax is somewhat awkward, every other type of nevow tag and |
---|
237 | attribute may be used inside the nevow:attr node. This makes setting attributes |
---|
238 | of tags uniform with every other method of manipulating the XML template. |
---|
239 |
|
---|
240 | nevow:invisible |
---|
241 | --------------- |
---|
242 |
|
---|
243 | Sometimes you need to group some elements, because you need to use a |
---|
244 | renderer for a group of children. |
---|
245 |
|
---|
246 | However, it may not be desirable to give these elements a parent/child |
---|
247 | relationship in your XML structure. For these cases, use nevow:invisible. |
---|
248 |
|
---|
249 | As suggested by the name, a nevow:invisible tag is removed in the rendered |
---|
250 | XML. Here is an example:: |
---|
251 | |
---|
252 | <html><nevow:invisible nevow:data="name" nevow:render="data" /></html> |
---|
253 |
|
---|
254 | With the data_name method:: |
---|
255 |
|
---|
256 | def data_name(self, ctx, data): |
---|
257 | return "Hello!" |
---|
258 |
|
---|
259 | Will result in the document:: |
---|
260 |
|
---|
261 | <html>Hello!</html> |
---|
262 |
|
---|
263 | xmlstr, htmlfile, and htmlstr |
---|
264 | ----------------------------- |
---|
265 |
|
---|
266 | xmlstr is a loader which is identical to xmlfile except it takes a string of XML |
---|
267 | directly. |
---|
268 |
|
---|
269 | htmlfile and htmlstr should generally be avoided. They are similar to xmlfile |
---|
270 | and xmlstr, except they use twisted.web.microdom in beExtremelyLenient mode to |
---|
271 | attempt to parse badly-formed HTML (non-XHTML) templates. See the nevow.loaders |
---|
272 | docstrings for more information. |
---|
273 |
|
---|
274 | Conclusions |
---|
275 | =========== |
---|
276 |
|
---|
277 | Nevow's xmlfile tag attribute language allows you to integrate |
---|
278 | externally-designed XHTML templates into the Nevow rendering process. |
---|
279 |
|
---|