Mercurial > genshi > mirror
comparison genshi/output.py @ 940:303af96ec546 stable-0.6.x
Merge r1163 and r1164 from trunk (fix Markup event caching issue in serializers, issue #429).
author | hodgestar |
---|---|
date | Sun, 12 Jun 2011 00:45:56 +0000 |
parents | 869ca3cc2f4c |
children | 26d6ac224d3b |
comparison
equal
deleted
inserted
replaced
928:a1fa93e72d69 | 940:303af96ec546 |
---|---|
75 method = {'xml': XMLSerializer, | 75 method = {'xml': XMLSerializer, |
76 'xhtml': XHTMLSerializer, | 76 'xhtml': XHTMLSerializer, |
77 'html': HTMLSerializer, | 77 'html': HTMLSerializer, |
78 'text': TextSerializer}[method.lower()] | 78 'text': TextSerializer}[method.lower()] |
79 return method(**kwargs) | 79 return method(**kwargs) |
80 | |
81 | |
82 def _prepare_cache(use_cache=True): | |
83 """Prepare a private token serialization cache. | |
84 | |
85 :param use_cache: boolean indicating whether a real cache should | |
86 be used or not. If not, the returned functions | |
87 are no-ops. | |
88 | |
89 :return: emit and get functions, for storing and retrieving | |
90 serialized values from the cache. | |
91 """ | |
92 cache = {} | |
93 if use_cache: | |
94 def _emit(kind, input, output): | |
95 cache[kind, input] = output | |
96 return output | |
97 _get = cache.get | |
98 else: | |
99 def _emit(kind, input, output): | |
100 return output | |
101 def _get(key): | |
102 pass | |
103 return _emit, _get, cache | |
80 | 104 |
81 | 105 |
82 class DocType(object): | 106 class DocType(object): |
83 """Defines a number of commonly used DOCTYPE declarations as constants.""" | 107 """Defines a number of commonly used DOCTYPE declarations as constants.""" |
84 | 108 |
202 cache=cache)) | 226 cache=cache)) |
203 if doctype: | 227 if doctype: |
204 self.filters.append(DocTypeInserter(doctype)) | 228 self.filters.append(DocTypeInserter(doctype)) |
205 self.cache = cache | 229 self.cache = cache |
206 | 230 |
231 def _prepare_cache(self): | |
232 return _prepare_cache(self.cache)[:2] | |
233 | |
207 def __call__(self, stream): | 234 def __call__(self, stream): |
208 have_decl = have_doctype = False | 235 have_decl = have_doctype = False |
209 in_cdata = False | 236 in_cdata = False |
210 | 237 _emit, _get = self._prepare_cache() |
211 cache = {} | |
212 cache_get = cache.get | |
213 if self.cache: | |
214 def _emit(kind, input, output): | |
215 cache[kind, input] = output | |
216 return output | |
217 else: | |
218 def _emit(kind, input, output): | |
219 return output | |
220 | 238 |
221 for filter_ in self.filters: | 239 for filter_ in self.filters: |
222 stream = filter_(stream) | 240 stream = filter_(stream) |
223 for kind, data, pos in stream: | 241 for kind, data, pos in stream: |
224 cached = cache_get((kind, data)) | 242 if kind is TEXT and isinstance(data, Markup): |
243 yield data | |
244 continue | |
245 cached = _get((kind, data)) | |
225 if cached is not None: | 246 if cached is not None: |
226 yield cached | 247 yield cached |
227 | |
228 elif kind is START or kind is EMPTY: | 248 elif kind is START or kind is EMPTY: |
229 tag, attrib = data | 249 tag, attrib = data |
230 buf = ['<', tag] | 250 buf = ['<', tag] |
231 for attr, value in attrib: | 251 for attr, value in attrib: |
232 buf += [' ', attr, '="', escape(value), '"'] | 252 buf += [' ', attr, '="', escape(value), '"'] |
321 boolean_attrs = self._BOOLEAN_ATTRS | 341 boolean_attrs = self._BOOLEAN_ATTRS |
322 empty_elems = self._EMPTY_ELEMS | 342 empty_elems = self._EMPTY_ELEMS |
323 drop_xml_decl = self.drop_xml_decl | 343 drop_xml_decl = self.drop_xml_decl |
324 have_decl = have_doctype = False | 344 have_decl = have_doctype = False |
325 in_cdata = False | 345 in_cdata = False |
326 | 346 _emit, _get = self._prepare_cache() |
327 cache = {} | |
328 cache_get = cache.get | |
329 if self.cache: | |
330 def _emit(kind, input, output): | |
331 cache[kind, input] = output | |
332 return output | |
333 else: | |
334 def _emit(kind, input, output): | |
335 return output | |
336 | 347 |
337 for filter_ in self.filters: | 348 for filter_ in self.filters: |
338 stream = filter_(stream) | 349 stream = filter_(stream) |
339 for kind, data, pos in stream: | 350 for kind, data, pos in stream: |
340 cached = cache_get((kind, data)) | 351 if kind is TEXT and isinstance(data, Markup): |
352 yield data | |
353 continue | |
354 cached = _get((kind, data)) | |
341 if cached is not None: | 355 if cached is not None: |
342 yield cached | 356 yield cached |
343 | 357 |
344 elif kind is START or kind is EMPTY: | 358 elif kind is START or kind is EMPTY: |
345 tag, attrib = data | 359 tag, attrib = data |
452 boolean_attrs = self._BOOLEAN_ATTRS | 466 boolean_attrs = self._BOOLEAN_ATTRS |
453 empty_elems = self._EMPTY_ELEMS | 467 empty_elems = self._EMPTY_ELEMS |
454 noescape_elems = self._NOESCAPE_ELEMS | 468 noescape_elems = self._NOESCAPE_ELEMS |
455 have_doctype = False | 469 have_doctype = False |
456 noescape = False | 470 noescape = False |
457 | 471 _emit, _get = self._prepare_cache() |
458 cache = {} | |
459 cache_get = cache.get | |
460 if self.cache: | |
461 def _emit(kind, input, output): | |
462 cache[kind, input] = output | |
463 return output | |
464 else: | |
465 def _emit(kind, input, output): | |
466 return output | |
467 | 472 |
468 for filter_ in self.filters: | 473 for filter_ in self.filters: |
469 stream = filter_(stream) | 474 stream = filter_(stream) |
470 for kind, data, _ in stream: | 475 for kind, data, _ in stream: |
471 output = cache_get((kind, data)) | 476 if kind is TEXT and isinstance(data, Markup): |
477 yield data | |
478 continue | |
479 output = _get((kind, data)) | |
472 if output is not None: | 480 if output is not None: |
473 yield output | 481 yield output |
474 if (kind is START or kind is EMPTY) \ | 482 if (kind is START or kind is EMPTY) \ |
475 and data[0] in noescape_elems: | 483 and data[0] in noescape_elems: |
476 noescape = True | 484 noescape = True |
624 if prefixes is not None: | 632 if prefixes is not None: |
625 self.prefixes.update(prefixes) | 633 self.prefixes.update(prefixes) |
626 self.cache = cache | 634 self.cache = cache |
627 | 635 |
628 def __call__(self, stream): | 636 def __call__(self, stream): |
629 cache = {} | |
630 cache_get = cache.get | |
631 if self.cache: | |
632 def _emit(kind, input, output, pos): | |
633 cache[kind, input] = output | |
634 return kind, output, pos | |
635 else: | |
636 def _emit(kind, input, output, pos): | |
637 return output | |
638 | |
639 prefixes = dict([(v, [k]) for k, v in self.prefixes.items()]) | 637 prefixes = dict([(v, [k]) for k, v in self.prefixes.items()]) |
640 namespaces = {XML_NAMESPACE.uri: ['xml']} | 638 namespaces = {XML_NAMESPACE.uri: ['xml']} |
639 _emit, _get, cache = _prepare_cache(self.cache) | |
641 def _push_ns(prefix, uri): | 640 def _push_ns(prefix, uri): |
642 namespaces.setdefault(uri, []).append(prefix) | 641 namespaces.setdefault(uri, []).append(prefix) |
643 prefixes.setdefault(prefix, []).append(uri) | 642 prefixes.setdefault(prefix, []).append(uri) |
644 cache.clear() | 643 cache.clear() |
645 def _pop_ns(prefix): | 644 def _pop_ns(prefix): |
666 val += 1 | 665 val += 1 |
667 yield 'ns%d' % val | 666 yield 'ns%d' % val |
668 _gen_prefix = _gen_prefix().next | 667 _gen_prefix = _gen_prefix().next |
669 | 668 |
670 for kind, data, pos in stream: | 669 for kind, data, pos in stream: |
671 output = cache_get((kind, data)) | 670 if kind is TEXT and isinstance(data, Markup): |
671 yield kind, data, pos | |
672 continue | |
673 output = _get((kind, data)) | |
672 if output is not None: | 674 if output is not None: |
673 yield kind, output, pos | 675 yield kind, output, pos |
674 | 676 |
675 elif kind is START or kind is EMPTY: | 677 elif kind is START or kind is EMPTY: |
676 tag, attrs = data | 678 tag, attrs = data |
699 prefix = namespaces[attrns][-1] | 701 prefix = namespaces[attrns][-1] |
700 if prefix: | 702 if prefix: |
701 attrname = '%s:%s' % (prefix, attrname) | 703 attrname = '%s:%s' % (prefix, attrname) |
702 new_attrs.append((attrname, value)) | 704 new_attrs.append((attrname, value)) |
703 | 705 |
704 yield _emit(kind, data, (tagname, Attrs(ns_attrs + new_attrs)), pos) | 706 data = _emit(kind, data, (tagname, Attrs(ns_attrs + new_attrs))) |
707 yield kind, data, pos | |
705 del ns_attrs[:] | 708 del ns_attrs[:] |
706 | 709 |
707 elif kind is END: | 710 elif kind is END: |
708 tagname = data.localname | 711 tagname = data.localname |
709 tagns = data.namespace | 712 tagns = data.namespace |
710 if tagns: | 713 if tagns: |
711 prefix = namespaces[tagns][-1] | 714 prefix = namespaces[tagns][-1] |
712 if prefix: | 715 if prefix: |
713 tagname = '%s:%s' % (prefix, tagname) | 716 tagname = '%s:%s' % (prefix, tagname) |
714 yield _emit(kind, data, tagname, pos) | 717 yield kind, _emit(kind, data, tagname), pos |
715 | 718 |
716 elif kind is START_NS: | 719 elif kind is START_NS: |
717 prefix, uri = data | 720 prefix, uri = data |
718 if uri not in namespaces: | 721 if uri not in namespaces: |
719 prefix = prefixes.get(uri, [prefix])[-1] | 722 prefix = prefixes.get(uri, [prefix])[-1] |