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
Copyright (C) 2012-2017 Edgewall Software