| 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 |
|
|---|