[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