title: Notes on SimpleTAL
subject: Notes, known limitations, and differences between SimpleTAL and Zope's ZPT.

<h2>Upgrading from SimpleTAL 4.x to 5.x</h2>
Porting SimpleTAL to Python 3 has introduced a number of small changes:

<ul>
<li>simpleTALUtils.HTMLStructureCleaner is not available from SimpleTAL 5 onwards.  The sgmlib library that it utilised was removed in Python 3.</li>
<li>simpleTAL.compileHTMLTemplate no longer accepts the inputEncoding argument.  All HTML templates must be either Strings or file objects that produce Strings.</li>
<li>compileDOMTemplate is not available from SimpleTAL 5 onwards.  The pyxml library that provides the Dom2SaxParser implementation is not yet available in Python 3.</li>
<li>simpleTALUtils.ExpandMacros defaults to utf-8 for outputEncoding rather than iso-8859-1.</li>
<li>simpleTALUtils.FastStringOutput has been removed in favour of the new io.StringIO which is faster.</li>
<li>simpleTALUtils.TemplateCache.getTemplate now defaults to utf-8 rather than iso-8859-1 for HTML templates.</li>
</ul>

<h2>Notes</h2>
Some notes on aspects of SimpleTAL that might require a little explanation.  If there is something you feel should be included in here, please let me know.

<h3><a name="htmlTemplates">HTML and XHTML Templates</a></h3>
SimpleTAL processes HTML templates slightly differently to XML templates.  In the HTML 4.01 specification there are several elements (e.g. &lt;img&gt;) for which end tags are forbidden.  This would normally cause a problem with TAL, because all tags that have TAL attributes on them must be closed.  To solve this problem SimpleTAL will:

<ul>
<li>Allow TAL attributes on all HTML elements that forbid close tags, and process them despite the lack of close tag</li>
<li>When compiling a HTML template issue a warning if a close tag is present for elements that are forbidden to have close tags.</li>
<li>Suppress the output of close tags for elements that are forbidden to have close tags.</li>
</ul>

These changes ensure that a HTML template can still be a valid HTML document, even if TAL needs to be used on elements that forbid end tags.  Additionally the output from the expanded template will also be valid HTML, in that the end tags will be suppressed even if present in the template.

As a consequence of this it is important that any XHTML templates are handled as XML rather than HTML, i.e. by calling compileXMLTemplate to compile the template.

<h3>Character set encoding</h3>
HTML templates can be provided as a string or a file like object that generates strings.  If loading from a file use open (filename, 'rt', encoding = "character-set") to load the template encoded in a particular character set.

XML templates specify within the document what encoding they use and so can be passed as a string, bytes, or a file like object.  When using strings the XML must have been originally in UTF-8.  To load from a file use open (filename, 'rb').

When expanding a template SimpleTAL will determine whether to write out strings if the output file is a sub-class of io.TextIOBase or codecs.StreamWriter.  Otherwise the file like object will be assumed to require bytes, and the output will be encoded first using 'outputEncoding', which defaults to utf-8.

<h3>Structured Content</h3>
When content is included into a template using 'tal:content' or 'tal:replace' the content is by default treated as text.  This means that the '&lt;', '&gt;' and '&amp;' characters will be automatically escaped so that they appear in the rendered template correctly.

When using the 'structure' keyword, however, SimpleTAL will pass the content straight through into the template with no escaping.  As such it's important to realise that the content placed into a template in such a way can affect the validity of the output.  For example if you take user input that contains HTML markup it's important to ensure that the markup is valid HTML, otherwise the resulting template output will not be valid.

<h3>Object Attributes versus Key Values</h3>
When adding a mapping object (e.g. a Dictionary) to the Context, care should be taken on the naming conventions used within the mapping.  When SimpleTAL resolves a path, it will first look for attributes on the object with that name, before trying to treat the object as a mapping object.  What this means in practice is that paths which match object attributes (e.g. methods) will never select the values given in the mapping.  As an example of this consider the following:

<pre>
<code>
Template:  &lt;p tal:repeat="item dict/items"&gt;&lt;b tal:replace="item"&gt;&lt;/b&gt;&lt;/p&gt;

Context:  
myDict = {'items': [1,2,3]}
Context.addGlobal ("dict", myDict)

</code>
</pre>

You would expect the output from this to be:

<pre>
<code>&lt;p&gt;1&lt;/p&gt;&lt;p&gt;2&lt;/p&gt;&lt;p&gt;3&lt;/p&gt;</code>
</pre>

However the variable "item" will be set to the output of "myDict.items()" - i.e. it will call the Python dictionary method 'items()'.

<h3>Using &lt; and &gt; in TAL Paths</h3>
When using the 'python:' path type, care must be taken with the use of the less than (&lt;) and greater than (&gt;) signs.  These must be escaped in the same way as all other HTML markup.  For example:

use: <code>&lt;div tal:condition="python: a &amp;lt; b"&gt;Conditional Text&lt;/div&gt;</code>
instead of: <code>&lt;div tal:condition="python: a &lt; b"&gt;Conditional Text&lt;/div&gt;</code>

<h2>Known limitations</h2>
<ol>
<li>Repeat Variables do not support 'first' and 'last'.</li>
<li>When using 'not:' on an empty expression the result will be true rather than an error.</li>
<li>Path type 'python:' is not supported by default.  You can enable this by passing allowPythonPath=1 to the Context constructor.  Note that this should only be used when the authors of the templates are completely trusted, the code included in the 'python:' path can do anything.</li>
<li>TAL markup "on-error" is not yet supported.</li>
<li>HTML Templates will have duplicate attributes if an attribute is added using "tal:attributes" and the name is in upper case.  The cause of this is the HTMLParser implementation, which always converts attributes to lower case.</li>
</ol>

<h2>Known differences</h2>
Non-existent path types, e.g. '&lt;b tal:content="total: $totalAmount"&gt;&lt;/b&gt;' are not supported.  In Zope, this results in the path being interpreted as a string - in simpleTAL/ES the result will be an error.

SimpleTAL 5.2 onwards supports accessing repeat variables through Python paths.  Unlike Zope, all variables on the repeat variable are methods, with the exception of length.  To access the value from a python path you need to call the method, e.g.: '&lt;b tal:content="python:repeat['item'].index()"&gt;&lt;/b&gt; 

<a href="index.html">Back to SimpleTAL</a>
