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 |
Nevow XML Templates
最新推荐文章于 2023-10-09 16:07:33 发布