diff markup/output.py @ 143:3d4c214c979a trunk

CDATA sections in XML input now appear as CDATA sections in the output. This should address the problem with escaping the contents of `<style>` and `<script>` elements, which would only get interpreted correctly if the output was served as `application/xhtml+xml`. Closes #24.
author cmlenz
date Fri, 11 Aug 2006 14:08:13 +0000
parents 520a5b7dd6d2
children 47bbd9d2a5af
line wrap: on
line diff
--- a/markup/output.py
+++ b/markup/output.py
@@ -23,7 +23,8 @@
 import re
 
 from markup.core import escape, Markup, Namespace, QName, XML_NAMESPACE
-from markup.core import DOCTYPE, START, END, START_NS, END_NS, TEXT, COMMENT, PI
+from markup.core import DOCTYPE, START, END, START_NS, END_NS, TEXT, \
+                        START_CDATA, END_CDATA, PI, COMMENT
 
 __all__ = ['Serializer', 'XMLSerializer', 'HTMLSerializer']
 
@@ -72,9 +73,10 @@
             self.filters.append(WhitespaceFilter(self._PRESERVE_SPACE))
 
     def __call__(self, stream):
-        have_doctype = False
         ns_attrib = []
         ns_mapping = {XML_NAMESPACE.uri: 'xml'}
+        have_doctype = False
+        in_cdata = False
 
         stream = chain(self.preamble, stream)
         for filter_ in self.filters:
@@ -125,7 +127,10 @@
                 yield Markup('</%s>' % tagname)
 
             elif kind is TEXT:
-                yield escape(data, quotes=False)
+                if in_cdata:
+                    yield data
+                else:
+                    yield escape(data, quotes=False)
 
             elif kind is COMMENT:
                 yield Markup('<!--%s-->' % data)
@@ -152,6 +157,14 @@
                     else:
                         ns_attrib.append((QName('xmlns:%s' % prefix), uri))
 
+            elif kind is START_CDATA:
+                yield Markup('<![CDATA[')
+                in_cdata = True
+
+            elif kind is END_CDATA:
+                yield Markup(']]>')
+                in_cdata = False
+
             elif kind is PI:
                 yield Markup('<?%s %s?>' % data)
 
@@ -182,6 +195,7 @@
         boolean_attrs = self._BOOLEAN_ATTRS
         empty_elems = self._EMPTY_ELEMS
         have_doctype = False
+        in_cdata = False
 
         stream = chain(self.preamble, stream)
         for filter_ in self.filters:
@@ -240,7 +254,10 @@
                 yield Markup('</%s>' % tagname)
 
             elif kind is TEXT:
-                yield escape(data, quotes=False)
+                if in_cdata:
+                    yield data
+                else:
+                    yield escape(data, quotes=False)
 
             elif kind is COMMENT:
                 yield Markup('<!--%s-->' % data)
@@ -267,6 +284,14 @@
                     else:
                         ns_attrib.append((QName('xmlns:%s' % prefix), uri))
 
+            elif kind is START_CDATA:
+                yield Markup('<![CDATA[')
+                in_cdata = True
+
+            elif kind is END_CDATA:
+                yield Markup(']]>')
+                in_cdata = False
+
             elif kind is PI:
                 yield Markup('<?%s %s?>' % data)
 
@@ -294,7 +319,7 @@
         super(HTMLSerializer, self).__init__(doctype, False)
         if strip_whitespace:
             self.filters.append(WhitespaceFilter(self._PRESERVE_SPACE,
-                                                 self._NOESCAPE_ELEMS))
+                                                 self._NOESCAPE_ELEMS, True))
 
     def __call__(self, stream):
         namespace = self.NAMESPACE
@@ -382,7 +407,7 @@
     _LINE_COLLAPSE = re.compile('\n{2,}')
     _XML_SPACE = XML_NAMESPACE['space']
 
-    def __init__(self, preserve=None, noescape=None):
+    def __init__(self, preserve=None, noescape=None, escape_cdata=False):
         """Initialize the filter.
         
         @param preserve: a set or sequence of tag names for which white-space
@@ -399,6 +424,7 @@
         if noescape is None:
             noescape = []
         self.noescape = frozenset(noescape)
+        self.escape_cdata = escape_cdata
 
     def __call__(self, stream, ctxt=None):
         trim_trailing_space = self._TRAILING_SPACE.sub
@@ -409,6 +435,7 @@
         preserve = False
         noescape_elems = self.noescape
         noescape = False
+        escape_cdata = self.escape_cdata
 
         textbuf = []
         push_text = textbuf.append
@@ -441,6 +468,12 @@
                 elif kind is END:
                     preserve = noescape = False
 
+                elif kind is START_CDATA and not escape_cdata:
+                    noescape = True
+
+                elif kind is END_CDATA and not escape_cdata:
+                    noescape = False
+
                 if kind:
                     yield kind, data, pos
 
Copyright (C) 2012-2017 Edgewall Software