Language Reference: Basics (TAL)

The template attribute language is used to create dynamic XML-like content. It allows elements of a document to be replaced, repeated, or omitted.


These are the available statements:

tal:defineDefine variables.
tal:switchDefines a switch condition
tal:conditionInclude element only if expression is true.
tal:repeatRepeat an element.
tal:caseIncludes element only if expression is equal to parent switch.
tal:contentSubstitute the content of an element.
tal:replaceReplace the element with dynamic content.
tal:omit-tagOmit the element tags, leaving only the inner content.
tal:attributesDynamically change or insert element attributes.
tal:on-errorSubstitute the content of an element if processing fails.

When there is only one TAL statement per element, the order in which they are executed is simple. Starting with the root element, each element’s statements are executed, then each of its child elements is visited, in order, to do the same:

    <title tal:content="context.title" />
    <div tal:condition="items">
      <p>These are your items:</p>
        <li tal:repeat="item items" tal:content="item" />

Any combination of statements may appear on the same element, except that the tal:content and tal:replace statements may not be used on the same element.

Note: The tal:case and tal:switch statements are available in Chameleon only.

TAL does not use the order in which statements are written in the tag to determine the order in which they are executed. When an element has multiple statements, they are executed in the order printed in the table above.

There is a reasoning behind this ordering. Because users often want to set up variables for use in other statements contained within this element or subelements, tal:define is executed first. Then any switch statement. tal:condition follows, then tal:repeat, then tal:case. We are now rendering an element; first tal:content or tal:replace. Finally, before tal:attributes, we havetal:omit-tag (which is implied with tal:replace).

Note: TALES is used as the expression language for the “stuff in the quotes”. The default syntax is simply Python, but other inputs are possible — see the section on expressions.


Removes, updates or inserts element attributes.

tal:attributes="href request.url"


tal:attributes syntax:

argument             ::= attribute_statement [';' attribute_statement]*
attribute_statement  ::= (attribute_name expression | expression)
attribute_name       ::= [namespace-prefix ':'] Name
namespace-prefix     ::= Name


The tal:attributes statement replaces the value of an attribute (or drops, or creates an attribute) with a dynamic value. The value of each expression is converted to a string, if necessary.

Note: You can qualify an attribute name with a namespace prefix, for example html:table, if you are generating an XML document with multiple namespaces.

If an attribute expression evaluates to None, the attribute is deleted from the statement element (or simply not inserted).

If an attribute statement is just an expression, it must evaluate to a Python dict (or implement the methods update() and items() from the dictionary specification).

If the expression evaluates to the symbol default (a symbol which is always available when evaluating attributes), its value is defined as the default static attribute value. If there is no such default value, a return value of default will drop the attribute.

If you use tal:attributes on an element with an active tal:replace command, the tal:attributesstatement is ignored.

If you use tal:attributes on an element with a tal:repeat statement, the replacement is made on each repetition of the element, and the replacement expression is evaluated fresh for each repetition.

Note: If you want to include a semicolon (“;”) in an expression, it must be escaped by doubling it (“;;”). Similarly, you can escape expression interpolation using the “$” symbol by doubling it (“$$”).


Replacing a link:

<a href="/sample/link.html"
   tal:attributes="href context.url()"

Replacing two attributes:

<textarea rows="80" cols="20"
          tal:attributes="rows request.rows();cols request.cols()" />

A checkbox input:

<input type="checkbox" tal:attributes="checked True" />


Conditionally includes or omits an element:

<div tal:condition="comments">


tal:condition syntax:

argument ::= expression


The tal:condition statement includes the statement element in the template only if the condition is met, and omits it otherwise. If its expression evaluates to a true value, then normal processing of the element continues, otherwise the statement element is immediately removed from the template. For these purposes, the value nothing is false, and default has the same effect as returning a true value.

Note: Like Python itself, ZPT considers None, zero, empty strings, empty sequences, empty dictionaries, and instances which return a nonzero value from __len__ or which return false from __nonzero__; all other values are true, including default.


Test a variable before inserting it:

<p tal:condition="request.message" tal:content="request.message" />

Testing for odd/even in a repeat-loop:

<div tal:repeat="item range(10)">
  <p tal:condition="repeat.item.even">Even</p>
  <p tal:condition="repeat.item.odd">Odd</p>


Replaces the content of an element.


tal:content syntax:

argument ::= (['text'] | 'structure') expression


Rather than replacing an entire element, you can insert text or structure in place of its children with the tal:content statement. The statement argument is exactly like that of tal:replace, and is interpreted in the same fashion. If the expression evaluates to nothing, the statement element is left childless. If the expression evaluates to default, then the element’s contents are evaluated.

The default replacement behavior is text, which replaces angle-brackets and ampersands with their HTML entity equivalents. The structure keyword passes the replacement text through unchanged, allowing HTML/XML markup to be inserted. This can break your page if the text contains unanticipated markup (eg. text submitted via a web form), which is the reason that it is not the default.

Note: The structure keyword exists to provide backwards compatibility. In Chameleon, the structure: expression type provides the same functionality (also for inline expressions).


Inserting the user name:

<p tal:content="user.getUserName()">Fred Farkas</p>

Inserting HTML/XML:

<p tal:content="structure context.getStory()">
   Marked <b>up</b> content goes here.


Defines local variables.


tal:define syntax:

variable_name  ::= Name | '(' Name [',' Name]* ')'
define_var     ::= variable_name expression
define_scope   ::= (['local'] | 'global') define_var
argument       ::= define_scope [';' define_scope]*


The tal:define statement defines variables. When you define a local variable in a statement element, you can use that variable in that element and the elements it contains. If you redefine a variable in a contained element, the new definition hides the outer element’s definition within the inner element.

Note that valid variable names are any Python identifier string including underscore, although two or more leading underscores are disallowed (used internally by the compiler). Further, names are case-sensitive.

Variable names support basic iterable unpacking when surrounded by parenthesis. This also applies to the variable established by tal:repeat.

Note: This is a Chameleon-specific language extension.

Python builtins are always “in scope”, but most of them may be redefined (such as help). Exceptions are:: floatintlenlongstrNoneTrue and False.

In addition, the following names are reserved: econtextrcontexttranslatedecode and convert.

If the expression associated with a variable evaluates to nothing, then that variable has the value nothing, and may be used as such in further expressions. Likewise, if the expression evaluates todefault, then the variable has the value default, and may be used as such in further expressions.

You can define two different kinds of variables: local and global. When you define a local variable in a statement element, you can only use that variable in that element and the elements it contains. If you redefine a local variable in a contained element, the new definition hides the outer element’s definition within the inner element. When you define a global variables, you can use it in any element processed after the defining element. If you redefine a global variable, you replace its definition for the rest of the template.

Tip: Global variables may be changed by the execution of a macro if that macro also declares the variable to be global.

To set the definition scope of a variable, use the keywords local or global in front of the assignment. The default setting is local; thus, in practice, only the global keyword is used.

Note: If you want to include a semicolon (“;”) in an expression, it must be escaped by doubling it (“;;”).


Defining a variable:

tal:define="company_name 'Zope Corp, Inc.'"

Defining two variables, where the second depends on the first:

tal:define="mytitle context.title; tlen len(mytitle)"

Defining a local and global variable:

tal:define="global mytitle context.title; tlen len(mytitle)"

Unpacking a sequence:

tal:define="(key,value) ('a', 42)"

tal:switch and tal:case

Defines a switch clause.

<ul tal:switch="len(items) % 2">
  <li tal:case="True">odd</li>
  <li tal:case="False">even</li>


tal:case and tal:switch syntax:

argument ::= expression


The switch and case construct is a short-hand syntax for matching a set of expressions against a single parent.

The tal:switch statement is used to set a new parent expression and the contained tal:casestatements are then matched in sequence such that only the first match succeeds.

Note that the symbol default affirms the case precisely when no previous case has been successful. It should therefore be placed last.

Note: These statements are only available in Chameleon 2.x and not part of the ZPT specification.


<ul tal:switch="item.type">
  <li tal:case="'document'">
  <li tal:case="'folder'">
  <li tal:case="default">


Removes an element, leaving its contents.


tal:omit-tag syntax:

argument ::= [ expression ]


The tal:omit-tag statement leaves the contents of an element in place while omitting the surrounding start and end tags.

If the expression evaluates to a false value, then normal processing of the element continues and the tags are not omitted. If the expression evaluates to a true value, or no expression is provided, the statement element is replaced with its contents.

Note: Like Python itself, ZPT considers None, zero, empty strings, empty sequences, empty dictionaries, and instances which return a nonzero value from __len__ or which return false from __nonzero__; all other values are true, including default.


Unconditionally omitting a tag:

<div tal:omit-tag="" comment="This tag will be removed">
  <i>...but this text will remain.</i>

Conditionally omitting a tag:

<b tal:omit-tag="not:bold">I may be bold.</b>

The above example will omit the b tag if the variable bold is false.

Creating ten paragraph tags, with no enclosing tag:

<span tal:repeat="n range(10)"
  <p tal:content="n">1</p>


Repeats an element.


tal:repeat syntax:

argument      ::= variable_name expression
variable_name ::= Name


The tal:repeat statement replicates a sub-tree of your document once for each item in a sequence. The expression should evaluate to a sequence. If the sequence is empty, then the statement element is deleted, otherwise it is repeated for each value in the sequence. If the expression is default, then the element is left unchanged, and no new variables are defined.

The variable_name is used to define a local variable and a repeat variable. For each repetition, the local variable is set to the current sequence element, and the repeat variable is set to an iteration object.

Repeat variables

You use repeat variables to access information about the current repetition (such as the repeat index). The repeat variable has the same name as the local variable, but is only accessible through the built-in variable named repeat.

The following information is available from the repeat variable:

indexRepetition number, starting from zero.
numberRepetition number, starting from one.
evenTrue for even-indexed repetitions (0, 2, 4, …).
oddTrue for odd-indexed repetitions (1, 3, 5, …).
parityFor odd-indexed repetitions, this is ‘odd’, else ‘even’.
startTrue for the starting repetition (index 0).
endTrue for the ending, or final, repetition.
lengthLength of the sequence, which will be the total number of repetitions.
letterRepetition number as a lower-case letter: “a” – “z”, “aa” – “az”, “ba” – “bz”, …, “za” – “zz”, “aaa” – “aaz”, and so forth.
LetterUpper-case version of letter.
romanRepetition number as a lower-case roman numeral: “i”, “ii”, “iii”, “iv”, “v”, etc.
RomanUpper-case version of roman.

You can access the contents of the repeat variable using either dictionary- or attribute-style access, e.g. repeat['item'].start or repeat.item.start.

Note: For legacy compatibility, the attributes oddevennumberletterLetterroman, and Romanare callable (returning self).

Note: Earlier versions of this document, and the Zope 2 Page Templates Reference, referred to firstand last attributes for use with sorted sequences. These are not implemented in Chameleon or the Zope reference implementation zope.tales. Instead, you can use itertools.groupby(), as in the example below.


Iterating over a sequence of strings:

<p tal:repeat="txt ('one', 'two', 'three')">
   <span tal:replace="txt" />

Inserting a sequence of table rows, and using the repeat variable to number the rows:

  <tr tal:repeat="item here.cart">
      <td tal:content="repeat.item.number">1</td>
      <td tal:content="item.description">Widget</td>
      <td tal:content="item.price">$1.50</td>

Nested repeats:

<table border="1">
  <tr tal:repeat="row range(10)">
    <td tal:repeat="column range(10)">
      <span tal:define="x repeat.row.number;
                        y repeat.column.number;
                        z x * y"
            tal:replace="string:$x * $y = $z">1 * 1 = 1</span>

Grouping objects by type, drawing a rule between elements of different types:

<div tal:repeat="(type,objects) list(map(lambda g: (g[0], list(g[1])), itertools.groupby(objects, key=lambda o: o.meta_type)))"
     tal:define="itertools import:itertools">
  <h2 tal:content="type">Meta Type</h2>
  <p tal:repeat="object objects"
     tal:content="">Object ID</p>
  <hr />

Caution: It is important to fully realize the iterator produced by itertools.groupby(), as well as the iterator produced for each group, in the expression passed to tal:repeat. This is because the implementation of certain repeat variables, such as length and end requires Chameleon to look ahead in the iterator, consuming it faster than is visible. The iterator returned by itertools.groupby() is shared among all of its subgroups, so without the full reification of all the iterators, incorrect results will be produced.


Replaces an element.


tal:replace syntax:

argument ::= ['structure'] expression


The tal:replace statement replaces an element with dynamic content. It replaces the statement element with either text or a structure (unescaped markup). The body of the statement is an expression with an optional type prefix. The value of the expression is converted into an escaped string unless you provide the ‘structure’ prefix. Escaping consists of converting &amp; to &amp;amp;&lt; to &amp;lt;, and &gt; to &amp;gt;.

Note: If the inserted object provides an __html__ method, that method is called with the result inserted as structure. This feature is not implemented by ZPT.

If the expression evaluates to None, the element is simply removed. If the value is default, then the element is left unchanged.


Inserting a title:

<span tal:replace="context.title">Title</span>

Inserting HTML/XML:

<div tal:replace="structure table" />

Leave a Comment

Your email address will not be published.