Mercurial > genshi > mirror
diff genshi/filters/transform.py @ 720:acf7c5ee36e7 experimental-newctxt
newctxt branch: Merged revisions [678:835] via svnmerge from [source:trunk].
author | cmlenz |
---|---|
date | Fri, 11 Apr 2008 08:42:11 +0000 |
parents | 4d486f15c986 |
children |
line wrap: on
line diff
--- a/genshi/filters/transform.py +++ b/genshi/filters/transform.py @@ -43,13 +43,15 @@ The ``Transformer`` support a large number of useful transformations out of the box, but custom transformations can be added easily. + +:since: version 0.5 """ import re import sys from genshi.builder import Element -from genshi.core import Stream, Attrs, QName, TEXT, START, END, _ensure +from genshi.core import Stream, Attrs, QName, TEXT, START, END, _ensure, Markup from genshi.path import Path __all__ = ['Transformer', 'StreamBuffer', 'InjectorTransformation', 'ENTER', @@ -141,14 +143,12 @@ __slots__ = ['transforms'] - def __init__(self, path=None): + def __init__(self, path='.'): """Construct a new transformation filter. :param path: an XPath expression (as string) or a `Path` instance """ - self.transforms = [] - if path: - self.transforms.append(SelectTransformation(path)) + self.transforms = [SelectTransformation(path)] def __call__(self, stream): """Apply the transform filter to the marked stream. @@ -160,7 +160,8 @@ transforms = self._mark(stream) for link in self.transforms: transforms = link(transforms) - return Stream(self._unmark(transforms)) + return Stream(self._unmark(transforms), + serializer=getattr(stream, 'serializer', None)) def apply(self, function): """Apply a transformation to the stream. @@ -548,6 +549,10 @@ ... '<b>some bold text</b></body></html>') >>> print html | Transformer('body').substitute('(?i)some', 'SOME') <html><body>SOME text, some more text and <b>SOME bold text</b></body></html> + >>> tags = tag.html(tag.body('Some text, some more text and ', + ... Markup('<b>some bold text</b>'))) + >>> print tags.generate() | Transformer('body').substitute('(?i)some', 'SOME') + <html><body>SOME text, some more text and <b>SOME bold text</b></body></html> :param pattern: A regular expression object or string. :param replace: Replacement pattern. @@ -556,6 +561,16 @@ """ return self.apply(SubstituteTransformation(pattern, replace, count)) + def rename(self, name): + """Rename matching elements. + + >>> html = HTML('<html><body>Some text, some more text and ' + ... '<b>some bold text</b></body></html>') + >>> print html | Transformer('body/b').rename('strong') + <html><body>Some text, some more text and <strong>some bold text</strong></body></html> + """ + return self.apply(RenameTransformation(name)) + def trace(self, prefix='', fileobj=None): """Print events as they pass through the transform. @@ -732,7 +747,10 @@ yield None, prefix yield mark, event while True: - mark, event = stream.next() + try: + mark, event = stream.next() + except StopIteration: + yield None, element[-1] if not mark: break yield mark, event @@ -791,8 +809,8 @@ if mark: queue.append(event) else: - for event in flush(queue): - yield event + for queue_event in flush(queue): + yield queue_event yield None, event for event in flush(queue): yield event @@ -851,7 +869,33 @@ """ for mark, (kind, data, pos) in stream: if kind is TEXT: - data = self.pattern.sub(self.replace, data, self.count) + new_data = self.pattern.sub(self.replace, data, self.count) + if isinstance(data, Markup): + data = Markup(new_data) + else: + data = new_data + yield mark, (kind, data, pos) + + +class RenameTransformation(object): + """Rename matching elements.""" + def __init__(self, name): + """Create the transform. + + :param name: New element name. + """ + self.name = QName(name) + + def __call__(self, stream): + """Apply the transform filter to the marked stream. + + :param stream: The marked event stream to filter + """ + for mark, (kind, data, pos) in stream: + if mark is ENTER: + data = self.name, data[1] + elif mark is EXIT: + data = self.name yield mark, (kind, data, pos) @@ -912,9 +956,15 @@ :param stream: The marked event stream to filter """ for mark, event in stream: - if mark in (ENTER, OUTSIDE): + if mark is not None: for subevent in self._inject(): yield subevent + yield mark, event + while True: + mark, event = stream.next() + if not mark: + break + yield mark, event yield mark, event @@ -930,7 +980,10 @@ yield mark, event if mark: while True: - mark, event = stream.next() + try: + mark, event = stream.next() + except StopIteration: + break if not mark: break yield mark, event