Mercurial > genshi > genshi-test
comparison genshi/template/markup.py @ 902:09cc3627654c experimental-inline
Sync `experimental/inline` branch with [source:trunk@1126].
author | cmlenz |
---|---|
date | Fri, 23 Apr 2010 21:08:26 +0000 |
parents | de82830f8816 |
children |
comparison
equal
deleted
inserted
replaced
830:de82830f8816 | 902:09cc3627654c |
---|---|
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 # | 2 # |
3 # Copyright (C) 2006-2008 Edgewall Software | 3 # Copyright (C) 2006-2010 Edgewall Software |
4 # All rights reserved. | 4 # All rights reserved. |
5 # | 5 # |
6 # This software is licensed as described in the file COPYING, which | 6 # This software is licensed as described in the file COPYING, which |
7 # you should have received as part of this distribution. The terms | 7 # you should have received as part of this distribution. The terms |
8 # are also available at http://genshi.edgewall.org/wiki/License. | 8 # are also available at http://genshi.edgewall.org/wiki/License. |
34 """Implementation of the template language for XML-based templates. | 34 """Implementation of the template language for XML-based templates. |
35 | 35 |
36 >>> tmpl = MarkupTemplate('''<ul xmlns:py="http://genshi.edgewall.org/"> | 36 >>> tmpl = MarkupTemplate('''<ul xmlns:py="http://genshi.edgewall.org/"> |
37 ... <li py:for="item in items">${item}</li> | 37 ... <li py:for="item in items">${item}</li> |
38 ... </ul>''') | 38 ... </ul>''') |
39 >>> print tmpl.generate(items=[1, 2, 3]) | 39 >>> print(tmpl.generate(items=[1, 2, 3])) |
40 <ul> | 40 <ul> |
41 <li>1</li><li>2</li><li>3</li> | 41 <li>1</li><li>2</li><li>3</li> |
42 </ul> | 42 </ul> |
43 """ | 43 """ |
44 | 44 |
68 self.add_directives(self.DIRECTIVE_NAMESPACE, self) | 68 self.add_directives(self.DIRECTIVE_NAMESPACE, self) |
69 | 69 |
70 def _init_filters(self): | 70 def _init_filters(self): |
71 Template._init_filters(self) | 71 Template._init_filters(self) |
72 # Make sure the include filter comes after the match filter | 72 # Make sure the include filter comes after the match filter |
73 if self.loader: | 73 self.filters.remove(self._include) |
74 self.filters.remove(self._include) | 74 self.filters += [self._match, self._include] |
75 self.filters += [self._match] | |
76 if self.loader: | |
77 self.filters.append(self._include) | |
78 | 75 |
79 def _parse(self, source, encoding): | 76 def _parse(self, source, encoding): |
80 if not isinstance(source, Stream): | 77 if not isinstance(source, Stream): |
81 source = XMLParser(source, filename=self.filename, | 78 source = XMLParser(source, filename=self.filename, |
82 encoding=encoding) | 79 encoding=encoding) |
129 if cls is None: | 126 if cls is None: |
130 raise BadDirectiveError(tag.localname, | 127 raise BadDirectiveError(tag.localname, |
131 self.filepath, pos[1]) | 128 self.filepath, pos[1]) |
132 args = dict([(name.localname, value) for name, value | 129 args = dict([(name.localname, value) for name, value |
133 in attrs if not name.namespace]) | 130 in attrs if not name.namespace]) |
134 directives.append((cls, args, ns_prefix.copy(), pos)) | 131 directives.append((factory.get_directive_index(cls), cls, |
132 args, ns_prefix.copy(), pos)) | |
135 strip = True | 133 strip = True |
136 | 134 |
137 new_attrs = [] | 135 new_attrs = [] |
138 for name, value in attrs: | 136 for name, value in attrs: |
139 if name.namespace == namespace: | 137 if name.namespace == namespace: |
141 if cls is None: | 139 if cls is None: |
142 raise BadDirectiveError(name.localname, | 140 raise BadDirectiveError(name.localname, |
143 self.filepath, pos[1]) | 141 self.filepath, pos[1]) |
144 if type(value) is list and len(value) == 1: | 142 if type(value) is list and len(value) == 1: |
145 value = value[0][1] | 143 value = value[0][1] |
146 directives.append((cls, value, ns_prefix.copy(), | 144 directives.append((factory.get_directive_index(cls), |
147 pos)) | 145 cls, value, ns_prefix.copy(), pos)) |
148 else: | 146 else: |
149 new_attrs.append((name, value)) | 147 new_attrs.append((name, value)) |
150 new_attrs = Attrs(new_attrs) | 148 new_attrs = Attrs(new_attrs) |
151 | 149 |
152 if directives: | 150 if directives: |
153 directives.sort(self.compare_directives()) | 151 directives.sort() |
154 dirmap[(depth, tag)] = (directives, len(new_stream), | 152 dirmap[(depth, tag)] = (directives, len(new_stream), |
155 strip) | 153 strip) |
156 | 154 |
157 new_stream.append((kind, (tag, new_attrs), pos)) | 155 new_stream.append((kind, (tag, new_attrs), pos)) |
158 depth += 1 | 156 depth += 1 |
243 href, parse = includes.pop() | 241 href, parse = includes.pop() |
244 try: | 242 try: |
245 cls = { | 243 cls = { |
246 'xml': MarkupTemplate, | 244 'xml': MarkupTemplate, |
247 'text': NewTextTemplate | 245 'text': NewTextTemplate |
248 }[parse or 'xml'] | 246 }.get(parse) or self.__class__ |
249 except KeyError: | 247 except KeyError: |
250 raise TemplateSyntaxError('Invalid value for "parse" ' | 248 raise TemplateSyntaxError('Invalid value for "parse" ' |
251 'attribute of include', | 249 'attribute of include', |
252 self.filepath, *pos[1:]) | 250 self.filepath, *pos[1:]) |
253 stream.append((INCLUDE, (href, cls, fallback), pos)) | 251 stream.append((INCLUDE, (href, cls, fallback), pos)) |
309 to the stream. | 307 to the stream. |
310 """ | 308 """ |
311 match_templates = ctxt._match_templates | 309 match_templates = ctxt._match_templates |
312 | 310 |
313 tail = [] | 311 tail = [] |
314 def _strip(stream): | 312 def _strip(stream, append=tail.append): |
315 depth = 1 | 313 depth = 1 |
314 next = stream.next | |
316 while 1: | 315 while 1: |
317 event = stream.next() | 316 event = next() |
318 if event[0] is START: | 317 if event[0] is START: |
319 depth += 1 | 318 depth += 1 |
320 elif event[0] is END: | 319 elif event[0] is END: |
321 depth -= 1 | 320 depth -= 1 |
322 if depth > 0: | 321 if depth > 0: |
323 yield event | 322 yield event |
324 else: | 323 else: |
325 tail[:] = [event] | 324 append(event) |
326 break | 325 break |
327 | 326 |
328 for event in stream: | 327 for event in stream: |
329 | 328 |
330 # We (currently) only care about start and end events for matching | 329 # We (currently) only care about start and end events for matching |
354 pre_end = idx + 1 | 353 pre_end = idx + 1 |
355 if 'match_once' not in hints and 'not_recursive' in hints: | 354 if 'match_once' not in hints and 'not_recursive' in hints: |
356 pre_end -= 1 | 355 pre_end -= 1 |
357 inner = _strip(stream) | 356 inner = _strip(stream) |
358 if pre_end > 0: | 357 if pre_end > 0: |
359 inner = self._match(inner, ctxt, end=pre_end, **vars) | 358 inner = self._match(inner, ctxt, start=start, |
359 end=pre_end, **vars) | |
360 content = self._include(chain([event], inner, tail), ctxt) | 360 content = self._include(chain([event], inner, tail), ctxt) |
361 if 'not_buffered' not in hints: | 361 if 'not_buffered' not in hints: |
362 content = list(content) | 362 content = list(content) |
363 content = Stream(content) | |
363 | 364 |
364 # Make the select() function available in the body of the | 365 # Make the select() function available in the body of the |
365 # match template | 366 # match template |
366 selected = [False] | 367 selected = [False] |
367 def select(path): | 368 def select(path): |
368 selected[0] = True | 369 selected[0] = True |
369 return Stream(content).select(path, namespaces, ctxt) | 370 return content.select(path, namespaces, ctxt) |
370 vars = dict(select=select) | 371 vars = dict(select=select) |
371 | 372 |
372 # Recursively process the output | 373 # Recursively process the output |
373 template = _apply_directives(template, directives, ctxt, | 374 template = _apply_directives(template, directives, ctxt, |
374 vars) | 375 vars) |
385 pass | 386 pass |
386 | 387 |
387 # Let the remaining match templates know about the last | 388 # Let the remaining match templates know about the last |
388 # event in the matched content, so they can update their | 389 # event in the matched content, so they can update their |
389 # internal state accordingly | 390 # internal state accordingly |
390 for test in [mt[0] for mt in match_templates]: | 391 for test in [mt[0] for mt in match_templates[idx + 1:]]: |
391 test(tail[0], namespaces, ctxt, updateonly=True) | 392 test(tail[0], namespaces, ctxt, updateonly=True) |
392 | 393 |
393 break | 394 break |
394 | 395 |
395 else: # no matches | 396 else: # no matches |