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

被折叠的 条评论
为什么被折叠?



