# HG changeset patch # User athomas # Date 1197936221 0 # Node ID ee48a06a16d654cfb1a145a057ef330b1874edd3 # Parent 077c9142dca0c8e3e2f68a582f4ff33164f7b92e Applied patch from cboos, fixing #168. Thanks! diff --git a/genshi/filters/tests/transform.py b/genshi/filters/tests/transform.py --- a/genshi/filters/tests/transform.py +++ b/genshi/filters/tests/transform.py @@ -19,9 +19,12 @@ def suite(): from genshi.input import HTML + from genshi.core import Markup + from genshi.builder import tag suite = doctest.DocTestSuite(genshi.filters.transform, optionflags=doctest.NORMALIZE_WHITESPACE, - extraglobs={'HTML': HTML}) + extraglobs={'HTML': HTML, 'tag': tag, + 'Markup': Markup}) return suite if __name__ == '__main__': diff --git a/genshi/filters/transform.py b/genshi/filters/transform.py --- a/genshi/filters/transform.py +++ b/genshi/filters/transform.py @@ -51,7 +51,7 @@ 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', @@ -143,12 +143,15 @@ __slots__ = ['transforms'] - def __init__(self, path='.'): + def __init__(self, path=None): """Construct a new transformation filter. :param path: an XPath expression (as string) or a `Path` instance """ - self.transforms = [SelectTransformation(path)] + if path is not None: + self.transforms = [SelectTransformation(path)] + else: + self.transforms = [] def __call__(self, stream): """Apply the transform filter to the marked stream. @@ -549,6 +552,10 @@ ... 'some bold text') >>> print html | Transformer('body').substitute('(?i)some', 'SOME') SOME text, some more text and SOME bold text + >>> tags = tag.html(tag.body('Some text, some more text and ', + ... Markup('some bold text'))) + >>> print tags.generate() | Transformer('body').substitute('(?i)some', 'SOME') + SOME text, some more text and SOME bold text :param pattern: A regular expression object or string. :param replace: Replacement pattern. @@ -650,6 +657,9 @@ # indicate they are not really part of the stream. yield ATTR, (None, (QName(event[1][0] + '@*'), result), event[2]) yield None, event + elif isinstance(result, tuple): + print result + yield None, result elif result: yield None, (TEXT, unicode(result), (None, -1, -1)) else: @@ -865,7 +875,11 @@ """ 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) diff --git a/genshi/output.py b/genshi/output.py --- a/genshi/output.py +++ b/genshi/output.py @@ -176,21 +176,17 @@ stripped from the output :note: Changed in 0.4.2: The `doctype` parameter can now be a string. """ - self.preamble = [] - if doctype: - if isinstance(doctype, basestring): - doctype = DocType.get(doctype) - self.preamble.append((DOCTYPE, doctype, (None, -1, -1))) self.filters = [EmptyTagFilter()] if strip_whitespace: self.filters.append(WhitespaceFilter(self._PRESERVE_SPACE)) self.filters.append(NamespaceFlattener(prefixes=namespace_prefixes)) + if doctype: + self.filters.append(DocTypeInserter(doctype)) def __call__(self, stream): have_decl = have_doctype = False in_cdata = False - stream = chain(self.preamble, stream) for filter_ in self.filters: stream = filter_(stream) for kind, data, pos in stream: @@ -696,3 +692,36 @@ if kind: yield kind, data, pos + + +class DocTypeInserter(object): + """A filter that inserts the DOCTYPE declaration in the correct location, + after the XML declaration. + """ + def __init__(self, doctype): + """Initialize the filter. + + :param doctype: DOCTYPE as a string or DocType object. + """ + if isinstance(doctype, basestring): + doctype = DocType.get(doctype) + self.doctype_event = (DOCTYPE, doctype, (None, -1, -1)) + + def __call__(self, stream): + buffer = [] + doctype_inserted = False + for kind, data, pos in stream: + # Buffer whitespace TEXT and XML_DECL + if not doctype_inserted: + if kind is XML_DECL or (kind is TEXT and not data.strip()): + buffer.append((kind, data, pos)) + continue + + for event in buffer: + yield event + + yield self.doctype_event + + doctype_inserted = True + + yield (kind, data, pos)