Mercurial > genshi > mirror
changeset 519:9e11fa7f4603 trunk
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 | c1f2a859fd75 |
children | 203bd6a3c93d |
files | doc/filters.txt genshi/filters/transform.py |
diffstat | 2 files changed, 63 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/filters.txt +++ b/doc/filters.txt @@ -164,12 +164,14 @@ ... </body> ... </html>''') - >>> print html | Transformer('body//em').apply(unicode.upper, TEXT) \ - ... .unwrap().wrap(tag.u) + >>> print html | Transformer('body/em').apply(unicode.upper, TEXT) \ + ... .unwrap().wrap(tag.u).end() \ + ... .select('body/u') \ + ... .prepend('underlined ') <html> <head><title>Some Title</title></head> <body> - Some <u>BODY</u> text. + Some <u>underlined BODY</u> text. </body> </html> @@ -177,8 +179,9 @@ 1. matches any `<em>` element anywhere in the body, 2. uppercases any text nodes in the element, - 3. strips off the `<em>` start and close tags, and - 4. wraps the content in a `<u>` tag. + 3. strips off the `<em>` start and close tags, + 4. wraps the content in a `<u>` tag, and + 5. inserts the text `underlind` inside the `<u>` tag. A number of commonly useful transformations are available for this filter. Please consult the API documentation a complete list.
--- 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