[Checkins] SVN: z3c.pt/trunk/ Correctly handle CDATA-sections, even when using expression interpolation.

Malthe Borch mborch at gmail.com
Tue Aug 12 12:38:59 EDT 2008


Log message for revision 89741:
  Correctly handle CDATA-sections, even when using expression interpolation.

Changed:
  U   z3c.pt/trunk/CHANGES.txt
  U   z3c.pt/trunk/src/z3c/pt/clauses.py
  U   z3c.pt/trunk/src/z3c/pt/etree.py
  U   z3c.pt/trunk/src/z3c/pt/translation.py
  U   z3c.pt/trunk/src/z3c/pt/translation.txt

-=-
Modified: z3c.pt/trunk/CHANGES.txt
===================================================================
--- z3c.pt/trunk/CHANGES.txt	2008-08-12 15:42:39 UTC (rev 89740)
+++ z3c.pt/trunk/CHANGES.txt	2008-08-12 16:38:58 UTC (rev 89741)
@@ -4,6 +4,9 @@
 Version 1.0dev
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+- CDATA sections are now correctly preserved when using expression
+  interpolation. [malthe]
+
 - Expression results are now validated for XML correctness when the
   compiler is running in debug-mode. [malthe]
 

Modified: z3c.pt/trunk/src/z3c/pt/clauses.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/clauses.py	2008-08-12 15:42:39 UTC (rev 89740)
+++ z3c.pt/trunk/src/z3c/pt/clauses.py	2008-08-12 16:38:58 UTC (rev 89741)
@@ -457,7 +457,8 @@
             
     """
 
-    def __init__(self, tag, attributes={}, selfclosing=False, expression=None):
+    def __init__(self, tag, attributes={},
+                 selfclosing=False, expression=None, cdata=False):
         i = tag.find('}')
 
         if i != -1:
@@ -468,8 +469,12 @@
         self.selfclosing = selfclosing
         self.attributes = attributes
         self.expression = expression and Assign(expression)
+        self.cdata = cdata
         
     def begin(self, stream):
+        if self.cdata:
+            stream.out('<![CDATA['); return
+
         stream.out('<%s' % self.tag)
 
         static = filter(
@@ -556,6 +561,9 @@
             stream.out(">")
 
     def end(self, stream):
+        if self.cdata:
+            stream.out(']]>'); return
+            
         if not self.selfclosing:
             stream.out('</%s>' % self.tag)
 

Modified: z3c.pt/trunk/src/z3c/pt/etree.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/etree.py	2008-08-12 15:42:39 UTC (rev 89740)
+++ z3c.pt/trunk/src/z3c/pt/etree.py	2008-08-12 16:38:58 UTC (rev 89741)
@@ -1,6 +1,7 @@
 import htmlentitydefs
 import config
 import utils
+import cgi
 from StringIO import StringIO
 
 try:
@@ -17,11 +18,47 @@
         ns_lookup = lxml.etree.Namespace
 
     class ElementBase(lxml.etree.ElementBase):
+        def _init(self):
+            self._convert_cdata_sections()
+            
         def tostring(self):
             return lxml.etree.tostring(self)
 
+        def _convert_cdata_sections(self):
+            start = '<![CDATA['
+            end = ']]>'
+
+            text = self._raw_text or ""
+            tail = self._raw_tail or ""
+
+            if start in text:
+                before, rest = text.split(start, 1)
+                cdata, after = rest.split(end, 1)
+
+                element = parser.makeelement(
+                    utils.xml_attr('cdata'))
+                element.attrib[utils.tal_attr('cdata')] = ""
+                element.text = cdata
+                element.tail = after
+                
+                self.text = before
+                self.insert(0, element)
+                
+            if start in tail:
+                before, rest = tail.split(start, 1)
+                cdata, after = rest.split(end, 1)
+
+                element = parser.makeelement(
+                    utils.xml_attr('cdata'))
+                element.attrib[utils.tal_attr('cdata')] = ""
+                self.addnext(element)
+
+                element.text = cdata
+                element.tail = after
+                self.tail = before
+                
         @property
-        def raw_text(self):
+        def _raw_text(self):
             """Return raw text.
 
             CDATA sections are returned in their original formatting;
@@ -48,13 +85,13 @@
             return text
 
         @property
-        def raw_tail(self):
-            """Return raw text.
+        def _raw_tail(self):
+            """Return raw tail.
 
             CDATA sections are returned in their original formatting;
             the routine relies on the fact that ``tostring`` will
             output CDATA sections even though they're not present in
-            the .text-attribute.
+            the .tail-attribute.
             """
 
             if self.tail in ("", None):

Modified: z3c.pt/trunk/src/z3c/pt/translation.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/translation.py	2008-08-12 15:42:39 UTC (rev 89740)
+++ z3c.pt/trunk/src/z3c/pt/translation.py	2008-08-12 16:38:58 UTC (rev 89741)
@@ -164,20 +164,21 @@
         
         if self.text is not None:
             while self.text:
-                m = translator.interpolate(self.text)
+                text = self.text
+                m = translator.interpolate(text)
                 if m is None:
                     break
 
                 t = etree.element_factory(utils.tal_attr('interpolation'))
                 t.attrib['replace'] = "structure "+m.group('expression')
-                t.tail = self.text[m.end():]
+                t.tail = text[m.end():]
                 self.insert(0, t)
                 t.update()
 
                 if m.start() == 0:
-                    self.text = self.text[1:m.start()+1]
+                    self.text = text[1:m.start()+1]
                 else:
-                    self.text = self.text[:m.start()+1]
+                    self.text = text[:m.start()+1]
 
         if self.tail is not None:
             while self.tail:
@@ -254,7 +255,7 @@
             _.append(clauses.Repeat(variables[0], expression))
 
         # tag tail (deferred)
-        tail = self.raw_tail
+        tail = self.tail
         if tail and not self.metal_fillslot:
             if isinstance(tail, unicode):
                 tail = tail.encode('utf-8')
@@ -277,7 +278,8 @@
         if replace is None:
             selfclosing = self.text is None and not dynamic and len(self) == 0
             tag = clauses.Tag(self.tag, self._get_attributes(),
-                              expression=self.py_attrs, selfclosing=selfclosing)
+                              expression=self.py_attrs, selfclosing=selfclosing,
+                              cdata=self.tal_cdata is not None)
 
             if self._omit:
                 _.append(clauses.Condition(_not(self._omit), [tag],
@@ -289,7 +291,7 @@
                 _.append(tag)
 
         # tag text (if we're not replacing tag body)
-        text = self.raw_text
+        text = self.text
         if text and not dynamic:
             if isinstance(text, unicode):
                 text = text.encode('utf-8')
@@ -539,6 +541,8 @@
         utils.tal_attr('omit-tag'), lambda p: p.expression)
     tal_default_expression = utils.attribute(
         utils.tal_attr('default-expression'))
+    tal_cdata = utils.attribute(
+        utils.tal_attr('cdata'))
     metal_define = utils.attribute(
         utils.metal_attr('define-macro'), lambda p: p.method)
     metal_use = utils.attribute(
@@ -587,6 +591,7 @@
     tal_content = utils.attribute("content", lambda p: p.output)
     tal_omit = utils.attribute("omit-tag", lambda p: p.expression, u"")
     tal_default_expression = utils.attribute("default-expression", lambda p: p.name)
+    tal_cdata = utils.attribute("cdata")
     
     def _get_static_attributes(self):
         attributes = {}
@@ -598,7 +603,8 @@
                            'repeat',
                            'attributes',
                            'content',
-                           'omit-tag'):
+                           'omit-tag',
+                           'cdata'):
                 raise ValueError(
                     u"Attribute '%s' not allowed in the namespace '%s'" %
                     (key, self.nsmap[self.prefix]))

Modified: z3c.pt/trunk/src/z3c/pt/translation.txt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/translation.txt	2008-08-12 15:42:39 UTC (rev 89740)
+++ z3c.pt/trunk/src/z3c/pt/translation.txt	2008-08-12 16:38:58 UTC (rev 89741)
@@ -47,14 +47,16 @@
 :: CDATA blocks
   >>> print render("""\
   ... <div xmlns="http://www.w3.org/1999/xhtml">
-  ... /* <![CDATA[ */
+  ...   /* <![CDATA[ */
   ...   This is protected
-  ... /* ]]> */
+  ...   /* ]]> */
+  ...   <span>Not protected</span> <![CDATA[ This is protected ]]>
   ... </div>""", translate_xml)
     <div>
       /* <![CDATA[ */
       This is protected
       /* ]]> */
+      <span>Not protected</span> <![CDATA[ This is protected ]]>
     </div>
 
 :: Variables containing markup
@@ -69,13 +71,19 @@
 
 :: Variable expansion must preserve XML validity
 
+  >>> from z3c.pt import config
+  >>> config.VALIDATION = True
+  
   >>> print render("""\
   ... <div xmlns="http://www.w3.org/1999/xhtml">
   ...   ${message}
   ... </div>""", translate_xml, message="Hello, <em>World!")
   Traceback (most recent call last):
-  ...
-
+   ...
+  ExpatError: ...
+  
+  >>> config.VALIDATION = False
+  
 :: Unless we are in a CDATA block
 
   >>> print render("""\



More information about the Checkins mailing list