Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > media > contrib-release > by-pkgid > 8b32d38f0094104a5fd847636983daa8 > files > 30

zope-doc-2.11.2-11mdv2010.0.i586.rpm

<html>
<head>
<title>Chapter 9. Advanced Page Templates</title>
</head>
<body bgcolor="#FFFFFF">
<h1>Chapter 9. Advanced Page Templates</h1>
<p>  In Chapter 5, "Using Zope Page Templates" you learned the basics
  about Page Templates. In this chapter you'll learn about advanced
  techniques including new types of expressions and macros.</p><h2>  Advanced TAL</h2>
<p>    You've already learned about a few TAL statements. In this section
    we'll go over all TAL statements and their various options. Note,
    this material is covered more concisely in Appendix C, "Zope Page
    Templates Reference".</p><h3>    Advanced Content Insertion</h3>
<p>      You've already seen how <code>tal:content</code> and <code>tal:replace</code> work in
      Chapter 5, "Using Zope Page Templates". In this section you'll
      learn some advanced tricks for inserting content.</p><h4>      Inserting Structure</h4>
<p>        Normally, the <code>tal:replace</code> and <code>tal:content</code> statements
        escape HTML tags and entities in the text that they insert,
        converting <code>&lt;</code> to <code>&amp;lt;</code>, for instance.  If you actually want
        to insert the unquoted text, you need to precede the
        expression with the <code>structure</code> keyword.  For example:<pre>          &lt;p replace=&quot;structure here/story&quot;&gt;
            the &lt;b&gt;story&lt;/b&gt;
          &lt;/p&gt;</pre>
</p><p>        This feature is useful when you are inserting a fragment of
        HTML or XML that is stored in a property or generated by
        another Zope object.  For instance, you may have news items
        that contain simple HTML markup such as bold and italic text
        when they are rendered, and you want to preserve this when
        inserting them into a "Top News" page.  In this case, you
        might write:<pre>          &lt;p tal:repeat=&quot;newsItem here/topNews&quot;
             tal:content=&quot;structure newsItem&quot;&gt;
            A news item with&lt;code&gt;HTML&lt;/code&gt; markup.
          &lt;/p&gt;</pre>
</p><p>        This will insert the news items including their HTML markup
        into paragraphs.</p><h4>      Dummy Elements</h4>
<p>        You can include page elements that are visible in the template
        but not in generated text by using the built-in variable
        <code>nothing</code>, like this:<pre>          &lt;tr tal:replace=&quot;nothing&quot;&gt;
            &lt;td&gt;10213&lt;/td&gt;&lt;td&gt;Example Item&lt;/td&gt;&lt;td&gt;$15.34&lt;/td&gt;
          &lt;/tr&gt;</pre>
</p><p>        This can be useful for filling out parts of the page that will
        be populated with dynamic content.  For instance, a table that
        usually has ten rows will only have one row in the template.
        By adding nine dummy rows, the template's layout will look
        more like the final result.</p><p>        It's not always necessary to use the <code>tal:replace=&quot;nothing&quot;</code>
        trick to get dummy content into your Page Template. For
        example, you've already seen that anything inside a
        <code>tal:content</code> or <code>tal:replace</code> element is normally removed
        when the template is rendered. In these cases you don't have
        do anything special to make sure that dummy content is
        removed.</p><h4>      Default Content</h4>
<p>        You can leave the contents of a tag along by using the
        <code>default</code> expression with <code>tal:content</code> or <code>tal:replace</code>. For
        example:<pre>          &lt;p tal:content=&quot;default&quot;&gt;Spam&lt;p&gt;</pre>
</p><p>        This renders to:<pre>          &lt;p&gt;Spam&lt;/p&gt;</pre>
</p><p>        Most often you will want to selectively include default
        content, rather than always including it. For example:<pre>          &lt;p tal:content=&quot;python:here.getFood() or default&quot;&gt;Spam&lt;/p&gt;</pre>
</p><p>        Note: Python expressions are explained later in the
        chapter. If the <code>getFood</code> method returns a true value than its
        result will be inserted into the paragraph, otherwise it's
        Spam for dinner.</p><h3>    Advanced Tag Repetition</h3>
<p>      You've already seen most of what you can do with the
      <code>tal:repeat</code> statement in Chapter 5, "Using Zope Page
      Templates". This section covers a few advanced features of the
      <code>tal:repeat</code> statement.</p><h4>      Repeat Variables</h4>
<p>        One topic that bear more explanation is repeat
        variables. Repeat variables provide information about the
        current repetition. These attributes are available on <code>repeat</code>
        variables:<ul>
<li><em>index</em> - repetition number, starting from zero.</li>
<li><em>number</em> - repetition number, starting from one.</li>
<li><em>even</em> - true for even-indexed repetitions (0, 2, 4, ...).</li>
<li><em>odd</em> - true for odd-indexed repetitions (1, 3, 5, ...).</li>
<li><em>start</em> - true for the starting repetition (index 0).</li>
<li><em>end</em> - true for the ending, or final, repetition.</li>
<li><em>length</em> - length of the sequence, which will be the total number
            of repetitions.</li>
<li><em>letter</em> - count reps with lower-case letters: "a" - "z",
          "aa" - "az", "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz", and
          so forth.</li>
<li><em>Letter</em> - upper-case version of <em>letter</em>.</li>
</ul>
</p><p>        You can access the contents of a repeat variable using path
        expressions or Python expressions.  In path expressions, you
        write a three-part path consisting of the name <code>repeat</code>, the
        statement variable's name, and the name of the information you
        want, for example, <code>repeat/item/start</code>.  In Python expressions,
        you use normal dictionary notation to get the repeat variable,
        then attribute access to get the information, for example,
        'python:repeat['item'].start'.</p><h4>      Repetition Tips</h4>
<p>        Here are a couple practical tips that you may find
        useful. Some times you'd like to repeat a tag, but not have an
        enclosing tag. For example, you might want to repeat a number
        of paragraph tags, but there is no need to enclose them in
        another tag. You can do this with the <code>tal:omit-tag</code>
        statement:<pre>          &lt;div tal:repeat=&quot;quote here/getQuotes&quot;
               tal:omit-tag=&quot;&quot;&gt;
            &lt;p tal:content=&quot;quote&quot;&gt;quotation&lt;/p&gt;
          &lt;/div&gt;</pre>
</p><p>        The <code>tal:omit-tag</code> statement is described later in this
        chapter.</p><p>        While it's been mentioned before, it's worth saying again: you
        can nest <code>tal:repeat</code> statements inside each other. Each
        <code>tal:repeat</code> statement must have a different repeat variable
        name. Here's an example that shows a math times-table:<pre>          &lt;table border=&quot;1&quot;&gt;
            &lt;tr tal:repeat=&quot;x python:range(1, 13)&quot;&gt;
              &lt;div tal:repeat=&quot;y python:range(1, 13)&quot;
                   tal:omit-tag=&quot;&quot;&gt;
                &lt;td tal:content=&quot;python:'%d x %d = %d' % (x, y, x*y)&quot;&gt;
                  X x Y = Z
                &lt;/td&gt;
              &lt;/div&gt;
            &lt;/tr&gt;
          &lt;/table&gt;</pre>
</p><p>        This example uses Python expressions, and the <code>tal:omit-tag</code>
        statement both of which are covered later in this chapter.</p><p>        If you've done much work with the dtml-in DTML repetition
        statement, you will have encountered batching. Batching is the
        process of chopping up a large list into smaller lists. You
        typically use it to display a small number of items from a
        large list on a web page. Think of how a search engine batches
        its search results. The <code>tal:repeat</code> statement does not
        support batching, but Zope comes with a batching utility. See
        the section, "Batching" later in this chapter.</p><p>        Another useful feature that isn't supplied by <code>tal:repeat</code> is
        sorting. If you want to sort a list you can either use write
        your own sorting script (which is quite easy in Python) or you
        can use the <code>sequence.sort</code> utility function. Here's an
        example of how to sort a list of objects by title, and then by
        modification date:<pre>          &lt;table tal:define=&quot;objects here/objectValues;
                             sort_on python:(('title', 'nocase', 'asc'),
                                             ('bobobase_modification_time', 'cmp', 'desc'));
                             sorted_objects python:sequence.sort(objects, sort_on)&quot;&gt;
            &lt;tr tal:repeat=&quot;item sorted_objects&quot;&gt;
              &lt;td tal:content=&quot;item/title&quot;&gt;title&lt;/td&gt;
              &lt;td tal:content=&quot;item/bobobase_modification_time&quot;&gt;
                modification date&lt;/td&gt;  
            &lt;/tr&gt;
          &lt;/table&gt;</pre>
</p><p>      This example tries to make things clearer by defining the sort
      arguments outside the <code>sort</code> function.  You call the
      <code>sequence.sort</code> function takes a sequence and a description of
      how to sort it. In this example the description of how to sort
      the sequence is defined in the <code>sort_on</code> variable.  See Appendix
      B, "API Reference" for more information on the powerful
      <code>sequence.sort</code> function.</p><h3>    Advanced Attribute Control</h3>
<p>      You've already met the <code>tal:attributes</code> statement. You can use
      it to dynamically replace tag attributes, for example, the
      <code>href</code> attribute on an <code>a</code> element. You can replace more than
      one attribute on a tag by separating attributes with
      semicolons:<pre>        &lt;a href=&quot;link&quot;
           tal:attributes=&quot;href here/getLink;
                           class here/getClass&quot;&gt;link&lt;/a&gt;</pre>
</p><p>      You can also define attributes with XML namespaces. For example:<pre>        &lt;Description 
            dc:Creator=&quot;creator name&quot;
            tal:attributes=&quot;dc:Creator here/owner/getUserName&quot;&gt;
          Description&lt;/Description&gt;</pre>
</p><p>      Simply put the XML namespace prefix before the attribute name
      and you can create attributes with XML namespaces.</p><h3>    Defining Variables</h3>
<p>      You can define your own variable using the <code>tal:define</code>
      attribute. There are several reasons that you might want to do
      this. One reason is to avoid having to write long expressions
      repeatedly in a template. Another is to avoid having to call
      expensive methods repeatedly. You can define a variable once and
      then use it many times in a template. For example, here's a list
      that defines a variable and later tests it and repeats over it:<pre>        &lt;ul tal:define=&quot;items container/objectIds&quot;
            tal:condition=&quot;items&quot;&gt;
          &lt;li tal:repeat=&quot;item items&quot;&gt;
            &lt;p tal:content=&quot;item&quot;&gt;id&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;</pre>
</p><p>      The <code>tal:define</code> statement creates the variable <code>items</code>, which
      you can use it anywhere in the <code>ul</code> tag.  Notice also how you
      can have two TAL statement on the same <code>ul</code> tag.  See the
      section, "Interactions Between TAL Statements" later in this
      chapter for more information about using more than one statement
      on a tag.  In this case the first statement assigns the variable
      <code>items</code> and the second uses <code>items</code> in a condition to see
      whether or not it is false (in this case, an empty sequence) or
      true. If the <code>items</code> variable is false, then the <code>ul</code> tag is not
      shown.</p><p>      Now, suppose that instead of simply removing the list when there
      are no items, you want to show a message.  To do this, place the
      following before the list:<pre>        &lt;h4 tal:condition=&quot;not:container/objectIds&quot;&gt;There
        Are No Items&lt;/h4&gt;</pre>
</p><p>      The expression, <code>not:container/objectIds</code> is true when
      <code>container/objectIds</code> is false, and vice versa. See the section,
      "Not Expressions" later in this chapter for more information.</p><p>      You can't use your <code>items</code> variable here, because it isn't
      defined yet.  If you move the definition of <code>items</code> to the <code>h4</code>
      tag, then you can't use it in the <code>ul</code> tag any more, because it
      becomes a <em>local</em> variable of the <code>h4</code> tag.  You could place the
      definition on some tag that enclosed both the <code>h4</code> and the <code>ul</code>,
      but there is a simpler solution.  By placing the keyword
      <code>global</code> in front of the variable name, you can make the
      definition last from the <code>h4</code> tag to the bottom of the
      template:<pre>        &lt;h4 tal:define=&quot;global items container/objectIds&quot;
            tal:condition=&quot;not:items&quot;&gt;There Are No Items&lt;/h4&gt;     </pre>
</p><p>      You can define more than one variable using <code>tal:define</code> by
      separating them with semicolons. For example:<pre>        &lt;p tal:define=&quot;ids container/objectIds; 
                       title container/title&quot;&gt;</pre>
</p><p>      You can define as many variables as you wish. Each variable can
      have its own global or local scope. You can also refer to
      earlier defined variables in later definitions. For example:<pre>        &lt;p tal:define=&quot;title template/title;
                       tlen python:len(title);&quot;&gt;</pre>
</p><p>      With judicious use of <code>tal:define</code> you can improve the
      efficiency and readability of your templates.</p><h3>    Omitting Tags</h3>
<p>      You can remove tags with the <code>tal:omit-tag</code> statement. You will
      seldom need to use this TAL statement, but occasionally it's
      useful. The omit-tag attribute removes a tag, but does not
      affect the contents of the tag. For example:<pre>        &lt;b tal:omit-tag=&quot;&quot;&gt;&lt;i&gt;this&lt;/i&gt; stays&lt;/b&gt;</pre>
</p><p>      Renders to:<pre>        &lt;i&gt;this&lt;/i&gt; stays</pre>
</p><p>      At this level of usage, <code>tal:omit-tag</code> operates almost like
      <code>tal:replace=&quot;default&quot;</code>. However, <code>tal:omit-tag</code> is more useful
      when used in combination with other TAL statement such as
      <code>tal:repeat</code>. For example here's one way to create ten paragraph
      tags using <code>tal:repeat</code>:<pre>        &lt;span tal:repeat=&quot;n python:range(10)&quot;
              tal:omit-tag=&quot;&quot;&gt;
          &lt;p tal:content=&quot;n&quot;&gt;1&lt;/p&gt;
        &lt;/span&gt;</pre>
</p><p>      This will produce ten paragraph tags, however, the <code>span</code> tag
      will not appear in the output.</p><p>      The <code>tal:omit-tag</code> attribute takes an expression, though
      normally you'll simply use an empty expression. If the
      expression is true or there is no expression then the statement
      tag is removed. If the expression is false, then the tag is not
      omitted. This allows you to selectively remove tags depending on
      dynamic circumstances.</p><h3>    Error Handling  </h3>
<p>      If an error occurs in your page template, you can catch that
      error and show a useful error message to your user.  For
      example, suppose your template defines a
      variable using form data:<pre>        ...
        &lt;span tal:define=&quot;global prefs request/form/prefs&quot;
              tal:omit-tag=&quot;&quot; /&gt;
        ...</pre>
</p><p>      If Zope encounters a problem, like not being able to find the
      <code>prefs</code> variable in the form data, the entire page will break;
      you'll get an error page instead. Happily, you can avoid this
      kind of thing with limited error handling using the
      <code>tal:on-error</code> statement:<pre>        ...
        &lt;span tal:define=&quot;global prefs here/scriptToGetPreferences&quot;
              tal:omit-tag=&quot;&quot;
              tal:on-error=&quot;string:An error occurred&quot;&gt;
        ...</pre>
</p><p>      When an error is raised while rendering a template, Zope looks
      for a <code>tal:on-error</code> statement to handle the error. It first
      looks in the current tag, then on its enclosing tag, and so on
      until it reaches the top-level tag. When it finds an error
      handler, it replaces the contents of that tag with the error
      handling expression. In this case, the <code>span</code> tag will contain
      an error message.</p><p>      Typically you'll define an error handler on a tag that encloses
      a logical page element, for example a table. If an error crops
      up drawing the table, then the error handler can simply omit the
      table from the page, or else replace it with an error message of
      some sort.</p><p>      For more flexible error handling you can call a script. For
      example:<pre>        &lt;div tal:on-error=&quot;structure here/handleError&quot;&gt;
        ...
        &lt;/div&gt;</pre>
</p><p>      Any error that occurs inside the <code>div</code> will call the
      <code>handleError</code> script. Note that the <code>structure</code> option allows
      the script to return HTML. Your error handling script can
      examine the error and take various actions depending on the
      error. Your script gets access to the error through the <code>error</code>
      variable in the namespace. For example:<pre>        ## Script (Python) &quot;handleError&quot;
        ##bind namespace=_
        ##
        error=_['error']
        if error.type==ZeroDivisionError:
            return &quot;&lt;p&gt;Can't divide by zero.&lt;/p&gt;&quot;
        else
            return &quot;&quot;&quot;&lt;p&gt;An error occurred.&lt;/p&gt;
                      &lt;p&gt;Error type: %s&lt;/p&gt;
                      &lt;p&gt;Error value: %s&lt;/p&gt;&quot;&quot;&quot; % (error.type,
                                                   error.value)</pre>
</p><p>      Your error handling script can take all kinds of actions, for
      example, it might log the error by sending email.</p><p>      The <code>tal:on-error</code> statement is not meant for general purpose
      exception handling. For example, you shouldn't validate form
      input with in. You should use a script for that, since scripts
      allow you to do powerful exception handling. The <code>tal:on-error</code>
      statement is for dealing with unusual problems that can occur
      when rendering templates.</p><h3>    Interactions Between TAL Statements</h3>
<p>      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, and their statements
      are executed, and so on.</p><p>      However, it's possible to have more than one TAL statement on
      the same element. Any combination of statements may appear on
      the same element, except that the <code>tal:content</code> and
      <code>tal:replace</code> statements may not appear together.</p><p>      When an element has multiple statements, they are executed in
      this order:<ol>
<li> define</li>
<li> condition</li>
<li> repeat</li>
<li> content or replace</li>
<li> attributes</li>
<li> omit-tag</li>
</ol>
</p><p>      Since the <code>tal:on-error</code> statement is only invoked when an error
      occurs, it does not appear in the list.</p><p>      The reasoning behind this ordering goes like this: you often
      want to set up variables for use in other statements, so define
      comes first. The very next thing to do is decide whether this
      element will be included at all, so condition is next; since the
      condition may depend on variables you just set, it comes after
      define. It is valuable to be able to replace various parts of an
      element with different values on each iteration of a repeat, so
      repeat comes before content, replace and attributes. Content and
      replace can't both be used on the same element so they occur at
      the same place. Omit-tag comes last since no other statement are
      likely to depend on it and since it should come after define and
      repeat.</p><p>      Here's an example tag that includes several TAL 
      statements:<pre>        &lt;p tal:define=&quot;x /root/a/long/path/x | nothing&quot;
           tal:condition=&quot;x&quot;
           tal:content=&quot;x/txt&quot;
           tal:attributes=&quot;class x/class&quot;&gt;Ex Text&lt;/p&gt;</pre>
</p><p>      Notice how the <code>tal:define</code> statement is executed first, and the
      other statements rely on its results.</p><p>      There are three limits you should be aware of when combining TAL
      statements on elements:</p><ol>
<li> Only one of each kind of statement can be used on a single
      tag.  Since HTML does not allow multiple attributes with the
      same name. For example, you can't have two <code>tal:define</code> on the
      same tag.</li>
<li> Both of <code>tal:content</code> and <code>tal:replace</code> cannot be used on
      the same tag, since their functions conflict.</li>
<li> The order in which you write TAL attributes on a tag does
      not affect the order in which they execute.  No matter how
      you arrange them, the TAL statements on a tag always execute
      in the fixed order described earlier.</li>
</ol>
<p>      If you want to override the ordering of TAL statements, you must
      do so by enclosing the element in another element, possibly
      <code>div</code> or <code>span</code>, and placing some of the statements on this new
      element. For example suppose you want to loop over a series of
      items but skip some. Here's an attempt to write a template that
      loops over the numbers zero to nine and skips three:<pre>        &lt;!-- broken template --&gt;
        &lt;ul&gt;
          &lt;li tal:repeat=&quot;n python:range(10)&quot;
              tal:condition=&quot;python:n != 3&quot;
              tal:content=&quot;n&quot;&gt; 
            1
          &lt;/li&gt;
        &lt;/ul&gt;</pre>
</p><p>      This template doesn't work because the the condition is tested
      before the repeat is executed. The upshot is that the <code>n</code>
      variable is not defined until after it is tested. Here's a way
      around this problem:<pre>        &lt;ul&gt;
          &lt;div tal:repeat=&quot;n python:range(10)&quot;
               tal:omit-tag=&quot;&quot;&gt;
            &lt;li tal:condition=&quot;python:n != 3&quot;
                tal:content=&quot;n&quot;&gt; 
              1
            &lt;/li&gt;
          &lt;/div&gt;
        &lt;/ul&gt;</pre>
</p><p>      This template solves the problem by defining the <code>n</code> variable on
      an enclosing <code>div</code> tag. Notice that the <code>div</code> tag will not
      appear in the output on account of it's <code>tal:omit-tag</code>
      statement. This may be ugly, but it works. Perhaps future
      versions of Page Templates will solve this problem in a nicer
      fashion.</p><h3>    Form Processing</h3>
<p>      You can process forms in DTML using a common pattern called the
      "form/action pair".  A form/action pair consists of two DTML
      methods or document: one that contains a form that collects
      input from the user, and one that contains an action that is
      taken on that input and returns the user a response.  The form
      calls the action.  See Chapter 4, "Dynamic Content with DTML"
      for more information on the form/action pattern.</p><p>      Zope Page Templates don't work particularly well with the
      form/action pattern since it assumes that input processing and
      response presentation are handled by the same object (the
      action). Instead of the form/action pattern you should use
      form/action/response pattern with Page Templates. The form and
      response should be Page Templates and the action should be a
      script. The form template gathers the input and call the action
      script. The action script should process the input and return a
      response template. This pattern is more flexible than the
      form/action pattern since it allows the script to return any of
      a number of different response objects.</p><p>      For example here's a part of a form template:<pre>        ...
        &lt;form action=&quot;action&quot;&gt;
          &lt;input type=&quot;text&quot; name=&quot;name&quot;&gt;
          &lt;input type=&quot;text&quot; name=&quot;age:int&quot;&gt;
          &lt;input type=&quot;submit&quot;&gt;
        &lt;/form&gt;
        ...</pre>
</p><p>      This form could be processed by this script:<pre>        ## Script (Python) &quot;action&quot;
        ##parameters=name, age
        ##
        container.addPerson(name, age)
        return container.responseTemplate()</pre>
</p><p>      This script calls a method to process the inputs and then
      returns another template, the response. You can render a Page
      Template from Python by calling it. The response template
      typically contains an acknowledgment that the form has been
      correctly processed.</p><p>      The action script can do all kinds of things. It can validate
      input, handle errors, send email, and more.  Here's a sketch of
      how to validate input with an script:<pre>        ## Script (Python) &quot;action&quot;
        ##
        if not context.validateData(request):
            # if there's a problem return the form page template
            # along with an error message
            return context.formTemplate(error_message='Invalid data')

        # otherwise return the thanks page
        return context.responseTemplate()</pre>
</p><p>      This script validates the form input and returns the form
      template with an error message if there's a problem. You can
      pass Page Templates extra information with keyword
      arguments. The keyword arguments are available to the template
      as via the <code>options</code> built-in variable. So the form template in
      this example might include a section like this:<pre>        &lt;b tal:condition=&quot;options/error_message | nothing&quot;
           tal:content=&quot;options/error_message&quot;&gt;
          Error message goes here.
        &lt;/b&gt;</pre>
</p><p>      This example shows how you can display an error message that is
      passed to the template via keyword arguments.</p><p>      Depending on your application you may choose to redirect the
      user to a response Page Template instead of returning it
      directly. This results in twice as much network activity, but
      might be useful because it changes the URL displayed in the
      user's browser to the URL of the Page Template, rather than that
      of the action script.</p><p>      If you insist on doing a crummy job of things, you can always
      create a lame version of the form-action pair using Page
      Templates. You should only do this when you don't care about
      error handling and when the response will always be the same,
      not matter what the user submits. Since Page Templates don't
      have an equivalent of dtml-call, you can use one of any number
      of hacks to call an input processing method without inserting
      its results. For example:<pre>        &lt;span tal:define=&quot;unused here/processInputs&quot; 
              tal:omit-tag=&quot;&quot;/&gt;</pre>
</p><p>      This sample calls the <code>processInputs</code> method and assigns the
      result to the <code>unused</code> variable.</p><h2>  Expressions</h2>
<p>    You've already encountered Page Template expressions. Expressions
    provide values to template statements. For example, path
    expressions describe objects by giving them paths such as
    <code>request/form/age</code>, or <code>user/getUserName</code>. In this section you'll
    learn about all the different types of expressions, and variables.</p><h3>    Built-in Variables</h3>
<p>      Variables are names that you can use in expressions. You have
      already seen some examples of the built-in variables such as
      <code>template</code>, <code>user</code>, <code>repeat</code>, and <code>request</code>.  Here is the
      complete list of the other built-in variables and their uses:</p><dl>
<dt>      <code>nothing</code></dt>
<dd>A false value, similar to a blank string, that you
      can use in <code>tal:replace</code> or <code>tal:content</code> to erase a tag or its
      contents.  If you set an attribute to <code>nothing</code>, the attribute
      is removed from the tag (or not inserted), unlike a blank
      string.</dd>
<dt>      <code>default</code></dt>
<dd>A special value that doesn't change anything when
      used in <code>tal:replace</code>, <code>tal:content</code>, or <code>tal:attributes</code>.  It
      leaves the template text in place.</dd>
<dt>      <code>options</code></dt>
<dd>The keyword arguments, if any, that were passed
      to the template. Note: options are only available when a
      template is called from Python. When a template is rendered from
      the web, no options are present.</dd>
<dt>      <code>attrs</code></dt>
<dd>A dictionary of attributes of the current tag in the
      template.  The keys are the attributes names, and the values are
      the original values of the attributes in the template. This
      variable is rarely needed.</dd>
<dt>      <code>root</code></dt>
<dd>The root Zope object.  Use this to get Zope objects
      from fixed locations, no matter where your template is placed or
      called.</dd>
<dt>      <code>here</code></dt>
<dd>The object on which the template is being called.
      This is often the same as the <em>container</em>, but can be different
      if you are using acquisition.  Use this to get Zope objects that
      you expect to find in different places depending on how the
      template is called. The <code>here</code> variable is analogous to the
      <code>context</code> variable in Python-based scripts.</dd>
<dt>      <code>container</code></dt>
<dd>The container (usually a Folder) in which the
      template is kept.  Use this to get Zope objects from locations
      relative to the template's permanent home. The <code>container</code> and
      <code>here</code> variables refer to the same object when a template is
      called from its normal location. However, when a template is
      applied to another object (for example, a ZSQL Method) the
      <code>container</code> and <code>here</code> will not refer to the same object.</dd>
<dt>      <code>modules</code></dt>
<dd>The collection of Python modules available to
      templates.  See the section on writing Python expressions.</dd>
</dl>
<p>      You'll find examples of how to use these variables through out
      this chapter.</p><h3>    String Expressions</h3>
<p>      String expressions allow you to easily mix path expressions with
      text.  All of the text after the leading <code>string:</code> is taken and
      searched for path expressions.  Each path expression must be
      preceded by a dollar sign ('$').  Here are some examples:<pre>        &quot;string:Just text. There's no path here.&quot;
        &quot;string:copyright $year, by me.&quot;</pre>
</p><p>      If the path expression has more than one part, or needs to be
      separated from the text that follows it, it must be surrounded
      by braces ('{}'). For example:<pre>        &quot;string:Three ${vegetable}s, please.&quot;
        &quot;string:Your name is ${user/getUserName}!&quot;</pre>
</p><p>      Notice how in the example above, you need to surround the
      <code>vegetable</code> path with braces so that Zope doesn't mistake it for
      <code>vegetables</code>.</p><p>      Since the text is inside of an attribute value, you can only
      include a double quote by using the entity syntax <code>&amp;quot;</code>.
      Since dollar signs are used to signal path expressions, a
      literal dollar sign must be written as two dollar signs
      ('$$'). For example:<pre>        &quot;string:Please pay $$$dollars_owed&quot;
        &quot;string:She said, &amp;quot;Hello world.&amp;quot;&quot;</pre>
</p><p>       Some complex string formatting operations (such as search and
       replace or changing capitalization) can't easily be done with
       string expressions. For these cases, you should use Python
       expressions or Scripts.</p><h3>    Path Expressions</h3>
<p>      Path expressions refer to objects with a path that resembles a
      URL path. A path describes a traversal from object to
      object. All paths begin with a known object (such as a built-in
      variable, a repeat variable, or a user defined variable) and
      depart from there to the desired object. Here are some example
      paths expressions:<pre>        template/title
        container/files/objectValues
        user/getUserName
        container/master.html/macros/header
        request/form/address
        root/standard_look_and_feel.html</pre>
</p><p>      With path expressions you can traverse from an object to its
      sub-objects including properties and methods. You can also use
      acquisition in path expressions. See the section entitled
      "Calling Scripts from the Web" in Chapter 8, "Advanced Zope
      Scripting" for more information on acquisition and path
      traversal.</p><p>      Zope restricts object traversal in path expressions in the same
      way that it restricts object access via URLs. You must have
      adequate permissions to access an object in order to refer to it
      with a path expression. See Chapter 6, "Users and Security" for
      more information about object access controls.</p><h4>      Alternate Paths</h4>
<p>        The path <code>template/title</code> is guaranteed to exist every time
        the template is used, although it may be a blank string.  Some
        paths, such as <code>request/form/x</code>, may not exist during some
        renderings of the template.  This normally causes an error
        when Zope evaluates the path expression.</p><p>        When a path doesn't exist, you may have a fall-back path or
        value that you would like to use instead.  For instance, if
        <code>request/form/x</code> doesn't exist, you might want to use <code>here/x</code>
        instead.  You can do this by listing the paths in order of
        preference, separated by vertical bar characters ('|'):<pre>          &lt;h4 tal:content=&quot;request/form/x | here/x&quot;&gt;Header&lt;/h4&gt;</pre>
</p><p>        Two variables that are very useful as the last path in a list
        of alternates are <code>nothing</code> and <code>default</code>.  For example,
        <code>default</code> tells <code>tal:content</code> to leave the dummy
        content. Different TAL statements interpret <code>default</code> and
        <code>nothing</code> differently. See Appendix C, "Zope Page Templates
        Reference" for more information.</p><p>        You can also use a non-path expression as the final part in an
        alternate-path expression. For example:<pre>          &lt;p tal:content=&quot;request/form/age|python:18&quot;&gt;age&lt;/p&gt;</pre>
</p><p>        In this example, if the <code>request/form/age</code> path doesn't exist,
        then the value is the number 18. This form allows you to
        specify default values to use which can't be expressed as
        paths. Note, you can only use a non-path expression as the
        last alternative.</p><p>        You can also test the existence of a path directly with the
        <em>exists</em> expression type prefix. See the section "Exists
        Expressions" below for more information on exists expressions.</p><h3>    Not Expressions</h3>
<p>      Not expressions let you negate the value of other
      expressions. For example:<pre>        &lt;p tal:condition=&quot;not:here/objectIds&quot;&gt;
          There are no contained objects.
        &lt;/p&gt;</pre>
</p><p>      Not expressions return true when the expression they are applied
      to is false, and vice versa. In Zope, non-existent variables,
      zero, empty strings, empty sequences, nothing, and None are
      considered false, while everything else is true.</p><p>      There isn't much reason to use not expressions with Python
      expressions since you can use the Python <code>not</code> keyword instead.</p><h3>    Nocall Expressions</h3>
<p>      An ordinary path expression tries to render the object
      that it fetches.  This means that if the object is a function,
      Script, Method, or some other kind of executable thing, then
      expression will evaluate to the result of calling the object.
      This is usually what you want, but not always.  For example,
      if you want to put a DTML Document into a variable so that
      you can refer to its properties, you can't use a normal path
      expression because it will render the Document into a string.</p><p>      If you put the <code>nocall:</code> expression type prefix in front of a
      path, it prevents the rendering and simply gives you the
      object.  For example:<pre>        &lt;span tal:define=&quot;doc nocall:here/aDoc&quot;
              tal:content=&quot;string:${doc/getId}: ${doc/title}&quot;&gt;
        Id: Title&lt;/span&gt;</pre>
</p><p>      This expression type is also valuable when you want to define
      a variable to hold a function or class from a module, for use
      in a Python expression.</p><p>      Nocall expressions can also be used on functions, rather than
      objects:<pre>        &lt;p tal:define=&quot;join nocall:modules/string/join&quot;&gt;</pre>
</p><p>      This expression defines the <code>join</code> variable as a function
      ('string.join'), rather than the result of calling a function.</p><h3>    Exists Expressions</h3>
<p>      An exists expression is true if its path exists, and otherwise
      is false.  For example here's one way to display an error
      message only if it is passed in the request:<pre>        &lt;h4 tal:define=&quot;err request/form/errmsg | nothing&quot;
            tal:condition=&quot;err&quot; 
            tal:content=&quot;err&quot;&gt;Error!&lt;/h4&gt;</pre>
</p><p>      You can do the same thing more easily with an exists
      expression:<pre>        &lt;h4 tal:condition=&quot;exists:request/form/errmsg&quot;
            tal:content=&quot;request/form/errmsg&quot;&gt;Error!&lt;/h4&gt;</pre>
</p><p>      You can combine exists expressions with not expressions, for
      example:<pre>        &lt;p tal:condition=&quot;not:exists:request/form/number&quot;&gt;Please enter
        a number between 0 and 5&lt;/p&gt;</pre>
</p><p>      Note that in this example you can't use the expression,
      "not:request/form/number", since that expression will be true if
      the <code>number</code> variable exists and is zero.</p><h3>    Python Expressions</h3>
<p>      The Python programming language is a simple and expressive one.
      If you have never encountered it before, you should read one of
      the excellent tutorials or introductions available at the
      <a href="http://www.python.org">Python website</a>.</p><p>      A Page Template Python expression can contain anything that the
      Python language considers an expression.  You can't use
      statements such as <code>if</code> and <code>while</code>. In addition, Zope imposes
      some security restrictions to keep you from accessing protected
      information, changing secured data, and creating problems such
      as infinite loops. See Chapter Chapter 8, "Advanced Zope
      Scripting" for more information on Python security restrictions.</p><h4>      Comparisons</h4>
<p>        One place where Python expressions are practically necessary
        is in <code>tal:condition</code> statements.  You usually want to compare
        two strings or numbers, and there isn't any other way to do
        that without Python expressions. You can use the comparison
        operators <code>&lt;</code> (less than), <code>&gt;</code> (greater than), <code>==</code> (equal
        to), and <code>!=</code> (not equal to).  You can also use the boolean
        operators <code>and</code>, <code>not</code>, and <code>or</code>.  For example:<pre>          &lt;p tal:repeat=&quot;widget widgets&quot;&gt;
            &lt;span tal:condition=&quot;python:widget.type == 'gear'&gt;
            Gear #&lt;span tal:replace=&quot;repeat/widget/number&gt;1&lt;/span&gt;:
            &lt;span tal:replace=&quot;widget/name&quot;&gt;Name&lt;/span&gt;
            &lt;/span&gt;
          &lt;/p&gt;</pre>
</p><p>        This example loops over a collection of objects, testing each
        object's <code>type</code> attribute. </p><p>        Sometimes you want to choose different values inside a single
        statement based on one or more conditions.  You can do this
        with the <code>test</code> function, like this:<pre>          You &lt;span tal:define=&quot;name user/getUserName&quot;
               tal:replace=&quot;python:test(name=='Anonymous User',
                                       'need to log in', default)&quot;&gt;
                are logged in as
                &lt;span tal:replace=&quot;name&quot;&gt;Name&lt;/span&gt;
              &lt;/span&gt;</pre>
</p><p>        The <code>test</code> function works like an if/then/else statement. See
        Appendix A, "DTML Reference" for more information on the
        <code>test</code> function. Here's another example of how you can use the
        <code>test</code> function:<pre>          &lt;tr tal:define=&quot;oddrow repeat/item/odd&quot;
              tal:attributes=&quot;class python:test(oddrow, 'oddclass',
                                                'evenclass')&quot;&gt;</pre>
</p><p>        Without the <code>test</code> function you'd have to write two <code>tr</code>
        elements each with a different condition, one for even rows,
        and the other for odd rows.</p><h4>      Using other Expression Types</h4>
<p>        You can use other expression types inside of a Python
        expression.  Each expression type has a corresponding function
        with the same name, including: <code>path()</code>, <code>string()</code>,
        <code>exists()</code>, and <code>nocall()</code>.  This allows you to write
        expressions such as:<pre>          &quot;python:path('here/%s/thing' % foldername)&quot;
          &quot;python:path(string('here/$foldername/thing'))&quot;
          &quot;python:path('request/form/x') or default&quot;</pre>
</p><p>        The final example has a slightly different meaning than the
        path expression, "request/form/x | default", since it will use
        the default text if "request/form/x" doesn't exists <em>or</em> if it
        is false.</p><h4>      Getting at Zope Objects</h4>
<p>        Much of the power of Zope involves tying together specialized
        objects.  Your Page Templates can use Scripts, SQL Methods,
        Catalogs, and custom content objects.  In order to use these
        objects you have to know how to get access to them within Page
        Templates.</p><p>        Object properties are usually attributes, so you can get a
        template's title with the expression "template.title". Most
        Zope objects support acquisition, which allows you to get
        attributes from "parent" objects.  This means that the Python
        expression "here.Control_Panel" will acquire the Control Panel
        object from the root Folder.  Object methods are attributes,
        as in "here.objectIds" and "request.set".  Objects contained
        in a Folder can be accessed as attributes of the Folder, but
        since they often have Ids that are not valid Python
        identifiers, you can't use the normal notation.  For example,
        you cannot use this Python expression:<pre>          &quot;python:here.penguin.gif&quot;'. </pre>
</p><p>        You must write:<pre>          &quot;python:getattr(here, 'penguin.gif')&quot;</pre>
</p><p>        since Python doesn't support attribute names with periods.</p><p>        Some objects, such as <code>request</code>, <code>modules</code>, and Zope Folders
        support Python item access, for example:<pre>          request['URL']
          modules['math']
          here['thing']</pre>
</p><p>        When you use item access on a Folder, it doesn't try to
        acquire the name, so it will only succeed if there is actually
        an object with that Id contained in the Folder.</p><p>        As shown in previous chapters, path expressions allow you to
        ignore details of how you get from one object to the next.
        Zope tries attribute access, then item access.  You can
        write:<pre>          &quot;here/images/penguin.gif&quot;</pre>
</p><p>        instead of:<pre>          &quot;python:getattr(here.images, 'penguin.gif')&quot;</pre>
</p><p>        and:<pre>          &quot;request/form/x&quot; </pre>
</p><p>        instead of:<pre>          &quot;python:request.form['x']&quot;</pre>
</p><p>        The trade-off is that path expressions don't allow you to
        specify those details.  For instance, if you have a form
        variable named "get", you must write:<pre>          &quot;python:request.form['get']&quot;</pre>
</p><p>        since this path expression:<pre>          &quot;request/form/get&quot; </pre>
</p><p>        will evaluate to the "get" <em>method</em> of the form dictionary.</p><p>        If you prefer you can use path expressions inside Python
        expressions using the <code>path()</code> function, as described above.</p><h4>      Using Scripts</h4>
<p>        Script objects are often used to encapsulate business logic
        and complex data manipulation.  Any time that you find
        yourself writing lots of TAL statements with complicated
        expressions in them, you should consider whether you could do
        the work better in a Script. If you have trouble understanding your
        template statements and expressions, then it's better to
        simplify your Page Template and use Scripts for the complex
        stuff.</p><p>        Each Script has a list of parameters that it expects to be
        given when it is called.  If this list is empty, then you can
        use the Script by writing a path expression.  Otherwise, you
        will need to use a Python expression in order to supply the
        argument, like this:<pre>          &quot;python:here.myscript(1, 2)&quot;
          &quot;python:here.myscript('arg', foo=request.form['x'])&quot;</pre>
</p><p>        If you want to return more than one item of data from a Script
        to a Page Template, it is a good idea to return it in a
        dictionary.  That way, you can define a variable to hold all
        the data, and use path expressions to refer to each item.  For
        example, suppose the <code>getPerson</code> script returns a dictionary
        with <code>name</code> and <code>age</code> keys:<pre>          &lt;span tal:define=&quot;person here/getPerson&quot;
                tal:replace=&quot;string:${person/name} is ${person/age}&quot;&gt;
          Name is 30&lt;/span&gt; years old.</pre>
</p><p>        Of course, it's fine to return Zope objects and Python lists
        as well.</p><h4>      Calling DTML</h4>
<p>        Unlike Scripts, DTML Methods and Documents don't have an
        explicit parameter list.  Instead, they expect to be passed a
        client, a mapping, and keyword arguments.  They use these
        parameters to construct a namespace.  See Chapter 7 for more
        information on explicitly calling DTML.</p><p>        When the Zope publishes a DTML object through the web, it
        passes the context of the object as the client, and the
        REQUEST as the mapping.  When one DTML object calls another,
        it passes its own namespace as the mapping, and no client.</p><p>        If you use a path expression to render a DTML object, it will
        pass a namespace with <code>request</code>, <code>here</code>, and the template's
        variables already on it.  This means that the DTML object will
        be able to use the same names as if it were being published in
        the same context as the template, plus the variable names
        defined in the template.</p><h4>      Python Modules</h4>
<p>        The Python language comes with a large number of modules,
        which provide a wide variety of capabilities to Python
        programs.  Each module is a collection of Python functions,
        data, and classes related to a single purpose, such as
        mathematical calculations or regular expressions.</p><p>        Several modules, including "math" and "string", are available
        in Python expressions by default.  For example, you can get
        the value of pi from the math module by writing
        "python:math.pi".  To access it from a path expression,
        however, you need to use the <code>modules</code> variable,
        "modules/math/pi".</p><p>        The "string" module is hidden in Python expressions by the
        "string" expression type function, so you need to access it
        through the <code>modules</code> variable.  You can do this directly in
        an expression in which you use it, or define a global variable
        for it, like this:<pre>          tal:define=&quot;global mstring modules/string&quot;
          tal:replace=&quot;python:mstring.join(slist, ':')&quot;</pre>
</p><p>        In practice you'll rarely need to do this since you can use
        string methods most of the time rather than having to rely on
        functions in the string module.</p><p>        Modules can be grouped into packages, which are simply a way
        of organizing and naming related modules.  For instance,
        Zope's Python-based Scripts are provided by a collection of
        modules in the "PythonScripts" subpackage of the Zope
        "Products" package.  In particular, the "standard" module in
        this package provides a number of useful formatting functions
        that are standard in the DTML "var" tag.  The full name of
        this module is "Products.PythonScripts.standard", so you could
        get access to it using either of the following statements:<pre>          tal:define=&quot;global pps modules/Products/PythonScripts/standard&quot;
          tal:define=&quot;global pps python:modules['Products.PythonScripts.standard']&quot;</pre>
</p><p>        Most Python modules cannot be accessed from Page Templates,
        DTML, or Scripts unless you add Zope security assertions to
        them.  This procedure is outside the scope of this book. See
        the <em>Zope Developer's Guide</em> for more information.</p><h2>  Macros</h2>
<p>    So far, you've seen how page templates can be used to add dynamic
    behavior to individual web pages.  Another feature of page
    templates is the ability to reuse look and feel elements across
    many pages.</p><p>    For example, with Page Templates, you can have a site that has a
    standard look and feel.  No matter what the "content" of a page,
    it will have a standard header, side-bar, footer, and/or other
    page elements.  This is a very common requirement for web sites.</p><p>    You can reuse presentation elements across pages with <em>macros</em>.
    Macros define a section of a page that can be reused in other
    pages.  A macro can be an entire page, or just a chunk of a page
    such as a header or footer. After you define one or more macros in
    one Page Template, you can use them in other Page Templates.</p><h3>    Using Macros</h3>
<p>      You can define macros with tag attributes similar to TAL
      statements. Macro tag attributes are called Macro Expansion Tag
      Attribute Language (METAL) statements.  Here's an example macro
      definition:<pre>        &lt;p metal:define-macro=&quot;copyright&quot;&gt;
          Copyright 2001, &lt;em&gt;Foo, Bar, and Associates&lt;/em&gt; Inc.
        &lt;/p&gt;</pre>
</p><p>      This <code>metal:define-macro</code> statement defines a macro named
      "copyright". The macro consists of the <code>p</code> tag and its contents
      (including all contained tags).</p><p>      Macros defined in a Page Template are stored in the template's
      <code>macro</code> attribute.  You can use macros from other page template
      by referring to them through the <code>macros</code> attribute of the Page
      Template in which they are defined.  For example, suppose the
      <code>copyright</code> macro is in a Page Template called
      "master_page". Here's how to use <code>copyright</code> macro from another
      Page Template:<pre>        &lt;hr&gt;
        &lt;b metal:use-macro=&quot;container/master_page/macros/copyright&quot;&gt;
          Macro goes here
        &lt;/b&gt;</pre>
</p><p>      In this Page template, the <code>b</code> tag will be completely replaced
      by the macro when Zope renders the page:<pre>        &lt;hr&gt;
        &lt;p&gt;
          Copyright 2001, &lt;em&gt;Foo, Bar, and Associates&lt;/em&gt; Inc.
        &lt;/p&gt;</pre>
</p><p>      If you change the macro (for example, if the copyright holder
      changes their name) then all Page Templates that use the macro
      will automatically reflect the change.</p><p>      Notice how the macro is identified by a path expression using
      the <code>metal:use-macro</code> statement. The <code>metal:use-macro</code> statement
      replaces the statement element with the named macro. </p><h3>    Macro Details      </h3>
<p>      The <code>metal:define-macro</code> and <code>metal:use-macro</code> statements are
      pretty simple. However there are a few subtleties worth
      mentioning.</p><p>      A macro's name must be unique within the Page Template in which
      it's defined. You can define more than one macro in a template,
      but they all need to have different names.</p><p>      Normally you'll refer to a macro in a <code>metal:use-macro</code>
      statement with a path expression. However, you can use any
      expression type you wish so long as it returns a macro. For
      example:<pre>        &lt;p metal:use-macro=&quot;python:here.getMacro()&quot;&gt;
          Replaced with a dynamically determined macro,
          which is located by the getMacro script.
        &lt;/p&gt;</pre>
</p><p>      Using Python expressions to locate macros lets you dynamically
      vary which macro your template uses.</p><p>      You can use the <code>default</code> variable with the <code>metal:use-macro</code>
      statement:<pre>        &lt;p metal:use-macro=&quot;default&quot;&gt;
          This content remains - no macro is used
        &lt;/p&gt;</pre>
</p><p>      The result is the same as using default with <code>tal:content</code> and
      <code>tal:replace</code>, the statement element doesn't change. </p><p>      If you try to use the <code>nothing</code> variable with <code>metal:use-macro</code>
      you will get an error, since <code>nothing</code> is not a macro. If you
      want to use <code>nothing</code> to conditionally include a macro, you
      should instead enclose the <code>metal:use-macro</code> statement with a
      <code>tal:condition</code> statement.</p><p>      Zope handles macros first when rendering your templates. Then
      Zope evaluates TAL expressions. For example, consider this
      macro:<pre>        &lt;p metal:define-macro=&quot;title&quot;
           tal:content=&quot;template/title&quot;&gt;
          template's title
        &lt;/p&gt;</pre>
</p><p>      When you use this macro it will insert the title of the template
      in which the macro is used, <em>not</em> the title of the template in
      which the macro is defined. In other words, when you use a
      macro, it's like copying the text of a macro into your template
      and then rendering your template.</p><p>      If you check the <em>Expand macros when editing</em> option on the Page
      Template <em>Edit</em> view, then any macros that you use will be
      expanded in your template's source. This is Zope's default
      behavior, and in general this is what you want, since it allows
      you to edit a complete and valid page. Sometimes, however,
      especially when you're editing in the ZMI, rather than using a
      WYSIWYG editing tool, it's more convenient not to expand macros
      when editing. In these cases, simply uncheck the option.</p><h3>    Using Slots</h3>
<p>      Macros are much more useful if you can override parts of them
      when you use them.  You can do this by defining <em>slots</em> in the
      macro that you can fill in when you use the template. For
      example, consider a side bar macro:<pre>        &lt;p metal:define-macro=&quot;sidebar&quot;&gt;
          Links
          &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;/&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/products&quot;&gt;Products&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/support&quot;&gt;Support&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/contact&quot;&gt;Contact Us&lt;/a&gt;&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/p&gt;</pre>
</p><p>      This macro is fine, but suppose you'd like to include some
      additional information in the sidebar on some pages. One way to
      accomplish this is with slots:<pre>        &lt;p metal:define-macro=&quot;sidebar&quot;&gt;
          Links
          &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;/&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/products&quot;&gt;Products&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/support&quot;&gt;Support&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/contact&quot;&gt;Contact Us&lt;/a&gt;&lt;/li&gt;
          &lt;/ul&gt;
          &lt;span metal:define-slot=&quot;additional_info&quot;&gt;&lt;/span&gt;
        &lt;/p&gt;</pre>
</p><p>      When you use this macro you can choose to fill the slot like
      so:<pre>        &lt;p metal:fill-slot=&quot;container/master.html/macros/sidebar&quot;&gt;
          &lt;b metal:fill-slot=&quot;additional_info&quot;&gt;
            Make sure to check out our &lt;a href=&quot;/specials&quot;&gt;specials&lt;/a&gt;.
          &lt;/b&gt;
        &lt;/p&gt;</pre>
</p><p>      When you render this template the side bar will include the
      extra information that you provided in the slot:<pre>        &lt;p&gt;
          Links
          &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;/&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/products&quot;&gt;Products&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/support&quot;&gt;Support&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/contact&quot;&gt;Contact Us&lt;/a&gt;&lt;/li&gt;
          &lt;/ul&gt;
          &lt;b&gt;
            Make sure to check out our &lt;a href=&quot;/specials&quot;&gt;specials&lt;/a&gt;.
          &lt;/b&gt;
        &lt;/p&gt;</pre>
</p><p>      Notice how the <code>span</code> element that defines the slot is replaced
      with the <code>b</code> element that fills the slot.</p><h3>    Customizing Default Presentation</h3>
<p>      A common use of slot is to provide default presentation which
      you can customize. In the slot example in the last section, the
      slot definition was just an empty <code>span</code> element. However, you
      can provide default presentation in a slot definition. For
      example, consider this revised sidebar macro:<pre>        &lt;div metal:define-macro=&quot;sidebar&quot;&gt;
          &lt;p metal:define-slot=&quot;links&quot;&gt;
          Links
          &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;/&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/products&quot;&gt;Products&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/support&quot;&gt;Support&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/contact&quot;&gt;Contact Us&lt;/a&gt;&lt;/li&gt;
          &lt;/ul&gt;
          &lt;/p&gt;
          &lt;span metal:define-slot=&quot;additional_info&quot;&gt;&lt;/span&gt;
        &lt;/div&gt;</pre>
</p><p>      Now the sidebar is fully customizable. You can fill the links
      slot to redefine the sidebar links. However, if you choose not
      to fill the <code>links</code> slot then you'll get the default links,
      which appear inside the slot.</p><p>      You can even take this technique further by defining slots
      inside of slots. This allows you to override default
      presentation with a fine degree of precision. Here's a sidebar
      macro that defines slots within slots:<pre>        &lt;div metal:define-macro=&quot;sidebar&quot;&gt;
          &lt;p metal:define-slot=&quot;links&quot;&gt;
          Links
          &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;/&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/products&quot;&gt;Products&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/support&quot;&gt;Support&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;/contact&quot;&gt;Contact Us&lt;/a&gt;&lt;/li&gt;
            &lt;span metal:define-slot=&quot;additional_links&quot;&gt;&lt;/span&gt;
          &lt;/ul&gt;
          &lt;/p&gt;
          &lt;span metal:define-slot=&quot;additional_info&quot;&gt;&lt;/span&gt;
        &lt;/div&gt;</pre>
</p><p>      If you wish to customize the sidebar links you can either fill
      the <code>links</code> slot to completely override the links, or you can
      fill the <code>additional_links</code> slot to insert some extra links
      after the default links. You can nest slots as deeply as you
      wish.</p><h3>    Combining METAL and TAL</h3>
<p>      You can use both METAL and TAL statements on the same
      elements. For example:<pre>        &lt;ul metal:define-macro=&quot;links&quot;
            tal:repeat=&quot;link here/getLinks&quot;&gt;
          &lt;li&gt;
            &lt;a href=&quot;link url&quot;
               tal:attributes=&quot;url link/url&quot;
               tal:content=&quot;link/name&quot;&gt;link name&lt;/a&gt;
          &lt;/li&gt;
        &lt;/ul&gt;</pre>
</p><p>      Since METAL statements are evaluated before TAL statements,
      there are no conflicts. This example is also interesting since
      it customizes a macro without using slots. The macro calls the
      <code>getLinks</code> Script to determine the links. You can thus customize
      your site's links be redefining the <code>getLinks</code> Script at
      different locations within your site.</p><p>      It's not always easy to figure out the best way customize look
      and feel in different parts of your site. In general you should
      use slots to override presentation elements, and you should use
      Scripts to provide content dynamically. In the case of the links
      example, it's arguable whether links are content or
      presentation. Scripts probably provide a more flexible solution,
      especially if your site includes link content objects.</p><h3>    Whole Page Macros</h3>
<p>      Rather than using macros for chunks of presentation shared
      between pages, you can use macros to define entire pages. Slots
      make this possible.  Here's an example macro that defines an
      entire page:<pre>        &lt;html metal:define-macro=&quot;page&quot;&gt;
          &lt;head&gt;
            &lt;title tal:content=&quot;here/title&quot;&gt;The title&lt;/title&gt;
          &lt;/head&gt;

          &lt;body&gt;
            &lt;h1 metal:define-slot=&quot;headline&quot;
                tal:content=&quot;here/title&quot;&gt;title&lt;/h1&gt;

            &lt;p metal:define-slot=&quot;body&quot;&gt;
              This is the body.  
            &lt;/p&gt;

            &lt;span metal:define-slot=&quot;footer&quot;&gt;
              &lt;p&gt;Copyright 2001 Fluffy Enterprises&lt;/p&gt;
            &lt;/span&gt;

          &lt;/body&gt;
        &lt;/html&gt;</pre>
</p><p>      This macro defines a page with three slots, <code>headline</code>, <code>body</code>,
      and <code>footer</code>.  Notice how the <code>headline</code> slot includes a TAL
      statement to dynamically determine the headline content.</p><p>      You can then use this macro in templates for different types of
      content, or different parts of your site. For example here's how
      a template for news items might use this macro:<pre>       &lt;html metal:use-macro=&quot;container/master.html/macros/page&quot;&gt;

         &lt;h1 metal:fill-slot=&quot;headline&quot;&gt;
           Press Release: 
           &lt;span tal:replace=&quot;here/getHeadline&quot;&gt;Headline&lt;/span&gt;
         &lt;/h1&gt;

         &lt;p metal:fill-slot=&quot;body&quot;
            tal:content=&quot;here/getBody&quot;&gt;
           News item body goes here
         &lt;/p&gt;

       &lt;/html&gt;</pre>
</p><p>      This template redefines the <code>headline</code> slot to include the
      words, "Press Release" and call the <code>getHeadline</code> method on the
      current object. It also redefines the <code>body</code> slot to call the
      <code>getBody</code> method on the current object.</p><p>      The powerful thing about this approach is that you can now
      change the <code>page</code> macro and the press release template will be
      automatically updated. For example you could put the body of the
      page in a table and add a sidebar on the left and the press
      release template would automatically use these new presentation
      elements.</p><p>      This is a much more flexible solution to control page look and
      feel then the DTML <code>standard_html_header</code> and
      <code>standard_html_footer</code> solution. In fact, Zope comes with a
      stock page template in the root folder named
      <code>standard_template.pt</code> that includes a whole page macro with a
      <code>head</code> and <code>body</code> slot. Here's how you might use this macro in a
      template:<pre>        &lt;html metal:use-macro=&quot;here/standard_template.pt/macros/page&quot;&gt;
          &lt;div metal:fill-slot=&quot;body&quot;&gt;
            &lt;h1 tal:content=&quot;here/title&quot;&gt;Title&lt;/h1&gt;
            &lt;p tal:content=&quot;here/getBody&quot;&gt;Body text goes here&lt;/p&gt;
          &lt;/div&gt;
        &lt;/html&gt;</pre>
</p><p>      Using the <code>standard_template.pt</code> macro is very similar to using
      other whole page macros. The only subtlety worth pointing out is
      the path used to locate the macro. In this example the path
      begins with <code>here</code>. This means that Zope will search for the
      <code>standard_template.pt</code> object using acquisition starting at the
      object that the template is applied to. This allows you to
      customize the look and feel of templates by creating custom
      <code>standard_template.pt</code> objects in various locations. This is
      exactly the same trick that you can use to customize look and
      feel by overriding <code>standard_html_header</code> and
      <code>standard_html_footer</code> in site locations. However, with
      <code>standard_template.pt</code> you have more choices. You can choose to
      start the path to the macro with <code>root</code> or with <code>container</code>, as
      well as with <code>here</code>. If the path begins with <code>root</code> then you
      will always get the standard template which is located in the
      root folder. If the path begins with <code>container</code> then Zope will
      search for a standard template using acquisition starting in the
      folder where the template is defined. This allows you to
      customize look and feel of templates, but does not allow you to
      customize the look and feel of different objects based on their
      location in the site.</p><h2>  Caching Templates</h2>
<p>    While rendering Page Templates normally is quite fast, sometimes
    it's not fast enough. For frequently accessed pages, or page that
    take a long time to render, you may want to trade some dynamic
    behavior for speed. Caching lets you do this. For more information
    on caching see the "Cache Manager" section of Chapter 3, "Basic
    Objects".</p><p>    You can cache Page Templates using a cache manager in the same way
    that you cache other objects. To cache a Page Template, you must
    associate it with a cache manager. You can either do this by going
    to the <em>Cache</em> view of you Page Template and selecting the cache
    manager, or by going to the <em>Associate</em> view of your cache manager
    and locating your Page Template. </p><p>    Here's an example of how to cache a Page Template. First create a
    Python-based script name <code>long.py</code> with these contents:<pre>      ## Script (Python) &quot;long.py&quot;
      ##
      for i in range(500):
        for j in range(500):
          for k in range(5):
            pass
      return 'Done'</pre>
</p><p>    The purpose of this script is to take up a noticeable amount of
    execution time. Now create a Page Template that uses this script,
    for example:<pre>      &lt;html&gt;
        &lt;body&gt;
          &lt;p tal:content=&quot;here/long.py&quot;&gt;results&lt;/p&gt;
        &lt;/body&gt;
      &lt;/html&gt;</pre>
</p><p>    Now view this page. Notice how it takes a while to render. Now
    let's radically improve its rendering time with caching.  Create a
    Ram Cache Manager if you don't already have one. Make sure to
    create it within the same folder as your Page Template, or in a
    higher level. Now visit the <em>Cache</em> view of your Page
    Template. Choose the Ram Cache Manager you just created and click
    <em>Save Changes</em>.  Click the <em>Cache Settings</em> link to see how your
    Ram Cache Manager is configured.  By default, your cache stores
    objects for one hour (3600 seconds). You may want to adjust this
    number depending on your application. Now return to your Page
    Template and view it again. It should take a while for it to
    render. Now reload the page, and watch it render immediately. You
    can reload the page again and again, and it will always render
    immediately since the page is now cached.</p><p>    If you change your Page Template, then it will be removed from the
    cache. So the next time you view it, it will take a while to
    render. But after that it will render quickly since it will be
    cached again.</p><p>    Caching is a simple but very powerful technique for improving
    performance. You don't have to be a wizard to use caching, and it
    can provide great speed-ups. It's well worth your time to use
    caching for performance-critical applications.</p><h2>  Page Template Utilities</h2>
<p>    Zope Page Templates are powerful but simple. Unlike DTML, Page
    Templates don't give you a lot of convenience features for things
    like batching, drawing trees, sorting, etc. The creators of Page
    Templates wanted to keep them simple. However, you may miss some
    of the built-in features that DTML provides. To address these
    needs, Zope comes with utilities designed to enhance Page
    Templates.</p><h3>    Batching Large Sets of Information</h3>
<p>      When a user queries a database and gets a hundred results, it's
      often better to show them several pages with only twenty results
      per page, rather than putting all the results on one
      page. Breaking up large lists into smaller lists is called
      <em>batching</em>.</p><p>      Unlike DTML, which provides batching built into the language,
      Page Templates support batching by using a special <code>Batch</code>
      object that comes from the <code>ZTUtils</code> utility module.  See
      Appendix B, "API Reference", for more information on the
      <code>ZTUtils</code> Python module.</p><p>      Here's a simple example, showing how to create a <code>Batch</code>
      object:<pre>        &lt;ul tal:define=&quot;lots python:range(100);
                        batch python:modules['ZTUtils'].Batch(lots, 
                                                              size=10,
                                                              start=0)&quot;&gt;
          &lt;li tal:repeat=&quot;num batch&quot;
              tal:content=&quot;num&quot;&gt;0
          &lt;/li&gt;
        &lt;/ul&gt;</pre>
</p><p>      This example renders a list with 10 items (in this case, the
      numbers 0 through 9). The <code>Batch</code> object chops a long list up
      into groups or batches. In this case it broke a one hundred item
      list up into batches of ten items.</p><p>      You can display a different batch of ten items by passing a
      different start number:<pre>        &lt;ul tal:define=&quot;lots python:range(100);
                        batch python:modules['ZTUtils'].Batch(lots, 
                                                              size=10,
                                                              start=13)&quot;&gt;</pre>
</p><p>      This batch starts with the fourteenth item and ends with the
      twenty third item. In other words, it displays the numbers 13
      through 22. It's important to notice that the batch <code>start</code>
      argument is the <em>index</em> of the first item. Indexes count from
      zero, rather than from one. So index 13 points to the fourteenth
      item in the sequence. Python uses indexes to refer to list
      items. </p><p>      Normally when you use batches you'll want to include navigation
      elements on the page to allow users to go from batch to batch.
      Here's a full-blow batching example that shows how to navigate
      between batches:<pre>        &lt;html&gt;
          &lt;head&gt;
            &lt;title tal:content=&quot;template/title&quot;&gt;The title&lt;/title&gt;
          &lt;/head&gt;
          &lt;body tal:define=&quot;employees  here/getEmployees;
                            start python:path('request/start') or 0;
                            batch python:modules['ZTUtils'].Batch(employees, 
                                                                  size=10, 
                                                                  start=start);
                            previous python:batch.previous;
                            next python:batch.next&quot;&gt;

          &lt;p&gt;
            &lt;a tal:condition=&quot;previous&quot;
               tal:attributes=&quot;href string:${request/URL0}?start:int=${previous/first}&quot;
               href=&quot;previous_url&quot;&gt;previous&lt;/a&gt;
            &lt;a tal:condition=&quot;next&quot;
               tal:attributes=&quot;href string:${request/URL0}?start:int=${next/first}&quot;
               href=&quot;next_url&quot;&gt;next&lt;/a&gt;
          &lt;/p&gt;

          &lt;ul tal:repeat=&quot;employee batch&quot; &gt;
            &lt;li&gt;
              &lt;span tal:replace=&quot;employee/name&quot;&gt;Bob Jones&lt;/span&gt;
              makes $&lt;span tal:replace=&quot;employee/salary&quot;&gt;100,000&lt;/span&gt;
              a year.
            &lt;/li&gt;
          &lt;/ul&gt;

          &lt;/body&gt;
        &lt;/html&gt;</pre>
</p><p>      This example iterates over batches of results from the
      <code>getEmployees</code> ZSQL Method. It draws a <em>previous</em> and a <em>next</em>
      link as necessary to allow you to page through all the results a
      batch at a time.</p><p>      Take a look at the <code>tal:define</code> statement on the <code>body</code>
      element. It defines a bunch of batching variables. The
      <code>employees</code> variable is a potentially big list of employee
      objects returned by the <code>getEmployees</code> ZSQL Method.  The second
      variable, <code>start</code>, is either set to the value of <code>request/start</code>
      or to zero if there is no <code>start</code> variable in the request.  The
      <code>start</code> variable keeps track of where you are in the list of
      employees. The <code>batch</code> variable is a batch of ten items from the
      lists of employees. The batch starts at the location specified
      by the <code>start</code> variable. The <code>previous</code> and <code>next</code> variables
      refer to the previous and next batches (if any). Since all these
      variables are defined on the <code>body</code> element, they are available
      to all elements inside the body.</p><p>      Next let's look at the navigation links. They create hyper links
      to browse previous and next batches. The <code>tal:condition</code>
      statement first tests to see if there is a previous and next
      batch. If there is a previous or next batch, then the link is
      rendered, otherwise there is not link. The <code>tal:attributes</code>
      statement creates a link to the previous and next batches. The
      link is simply the URL or the current page ('request/URL0')
      along with a query string indicating the start index of the
      batch. For example, if the current batch starts with index 10,
      then the previous batch will start with an index of 0. The
      <code>first</code> variable of a batch gives its staring index, so in this
      case, <code>previous.start</code> would be 0.</p><p>      It's not important to fully understand the workings of this
      example. Simply copy it, or use a batching example created by
      the <em>Z Search Interface</em>. Later when you want to do more complex
      batching you can experiment by changing the example code. Don't
      forget to consult Appendix B, "API Reference" for more
      information on the <code>ZTUtils</code> module and <code>Batch</code> objects.</p><h3>    Miscellaneous Utilities</h3>
<p>      Zope provides a couple Python modules which may come in handy
      when using Page Templates. The <code>string</code>, <code>math</code>, and <code>random</code>
      modules can be used in Python expressions for string formatting,
      math function, and pseudo-random number generation. These same
      modules are available from DTML and Python-based scripts. See
      Appendix B, "API Reference" for more information on these
      modules.</p><p>      The <code>Products.PythonScripts.standard</code> module is designed to
      provide utilities to Python-based scripts, but it's also useful
      for Page Templates. It includes various string and number
      formatting functions. See Appendix B, "API Reference" for more
      information.</p><p>      As mentioned earlier in the chapter, the <code>sequence</code> module
      provides a handy <code>sort</code> function. See Appendix B, "API
      Reference" for the details.</p><p>      Finally the <code>AccessControl</code> module includes a function and a
      class which you'll need if you want to test access and to get
      the authenticated user. See Appendix B, "API Reference" for more
      information.</p><h2>  Conclusion</h2>
<p>    This chapter covers all the nooks and crannies of Page Templates,
    and after reading it you may feel a little overwhelmed. Don't
    worry, you don't need to know everything in this chapter to
    effectively use Page Templates. You should understand the different
    path types and macros, but you can come back to the rest of the
    material when you need it. The advanced features that you've
    learned about in this chapter are there for you when you need
    them. It's encouraging to know that when you're ready you can do
    some pretty impressive tricks with Page Templates.</p></body>
</html>