Mercurial > genshi > genshi-test
diff genshi/filters/transform.py @ 519:9f1d90d6abd4
Cut and copy transformer operations can now operate on selected attributes.
Also added an example of inserting content to the documentation.
author | athomas |
---|---|
date | Thu, 07 Jun 2007 18:03:02 +0000 |
parents | 97cdadc17e20 |
children | 6bb05c0480fe |
line wrap: on
line diff
--- a/genshi/filters/transform.py +++ b/genshi/filters/transform.py @@ -76,9 +76,8 @@ """Stream augmentation mark indicating that a match occurred outside a selected element.""" -ATTRIBUTE = TransformMark('ATTRIBUTE') -"""Stream augmentation mark indicating that a an element attribute was -selected.""" +ATTR = TransformMark('ATTR') +"""Stream augmentation mark indicating a selected element attribute.""" EXIT = TransformMark('EXIT') """Stream augmentation mark indicating that a selected element is being @@ -301,10 +300,6 @@ :rtype: `Transformer` """ - def _unwrap(stream): - for mark, event in stream: - if mark not in (ENTER, EXIT): - yield mark, event return self | UnwrapTransformation() def wrap(self, element): @@ -469,6 +464,20 @@ >>> print buffer <em>body</em> + Element attributes can also be copied for later use: + + >>> html = HTML('<html><head><title>Some Title</title></head>' + ... '<body><em>Some</em> <em class="before">body</em>' + ... '<em>text</em>.</body></html>') + >>> buffer = StreamBuffer() + >>> def apply_attr(name, entry): + ... return list(buffer)[0][1][1].get('class') + >>> print html | Transformer('body/em[@class]/@class').copy(buffer) \\ + ... .end().select('body/em[not(@class)]').attr('class', apply_attr) + <html><head><title>Some Title</title></head><body><em + class="before">Some</em> <em class="before">body</em><em + class="before">text</em>.</body></html> + :param buffer: the `StreamBuffer` in which the selection should be stored @@ -543,7 +552,8 @@ def _unmark(self, stream): for mark, event in stream: - yield event + if event[0] is not None: + yield event class SelectTransformation(object): @@ -572,6 +582,8 @@ yield mark, event continue result = test(event, {}, {}) + # XXX This is effectively genshi.core._ensure() for transform + # streams. if result is True: if event[0] is START: yield ENTER, event @@ -589,9 +601,13 @@ test(subevent, {}, {}, updateonly=True) else: yield OUTSIDE, event + elif isinstance(result, Attrs): + # XXX Selected *attributes* are given a "kind" of None to + # indicate they are not really part of the stream. + yield ATTR, (None, (QName(event[1][0] + '@*'), result), event[2]) + yield None, event elif result: - yield None, event - yield ATTRIBUTE, result + yield None, (TEXT, unicode(result), (None, -1, -1)) else: yield None, event @@ -938,15 +954,41 @@ return stream -class CutTransformation(CopyTransformation, RemoveTransformation): +class CutTransformation(object): """Cut selected events into a buffer for later insertion and remove the selection. """ + def __init__(self, buffer): + """Create the cut transformation. + + :param buffer: the `StreamBuffer` in which the selection should be + stored + """ + self.buffer = buffer + def __call__(self, stream): """Apply the transform filter to the marked stream. :param stream: the marked event stream to filter """ - stream = CopyTransformation.__call__(self, stream) - return RemoveTransformation.__call__(self, stream) + out_stream = [] + attributes = None + for mark, (kind, data, pos) in stream: + if attributes: + assert kind is START + data = (data[0], data[1] - attributes) + attributes = None + if mark: + # There is some magic here. ATTR marked events are pushed into + # the stream *before* the START event they originated from. + # This allows cut() to strip out the attributes from START + # event as would be expected. + if mark is ATTR: + self.buffer.append((kind, data, pos)) + attributes = [name for name, _ in data[1]] + else: + self.buffer.append((kind, data, pos)) + else: + out_stream.append((mark, (kind, data, pos))) + return out_stream