Sophie

Sophie

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

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

<html>
<head>
<title>Chapter 5. Using Zope Page Templates</title>
</head>
<body bgcolor="#FFFFFF">
<h1>Chapter 5. Using Zope Page Templates</h1>
<p>  Page Templates are a web page generation tool.  They help
  programmers and designers collaborate in producing dynamic web pages
  for Zope web applications.  Designers can use them to maintain pages
  without having to abandon their tools, while preserving the work
  required to embed those pages in an application.  In this chapter,
  you'll learn the basics about Page Templates including how you can
  use them in your web site to create dynamic web pages easily. In
  Chapter 9, "Advanced Page Templates", you'll learn about advanced
  Page Template features.</p><p>  The goal of Page Templates is to allow designers and programmers to
  work together easily. A designer can use a WYSIWYG HTML editor to
  create a template, then a programmer can edit it to make it part of
  an application.  If required, the designer can load the template
  <em>back</em> into his editor and make further changes to its structure and
  appearance.  By taking reasonable steps to preserve the changes made
  by the programmer, the designer will not disrupt the application.</p><p>  Page Templates aim at this goal by adopting three principles:</p><ol>
<li> Play nicely with editing tools.</li>
<li> What you see is very similar to what you get.</li>
<li> Keep code out of templates, except for structural logic.</li>
</ol>
<p>  A Page Template is like a model of the pages that it will generate.
  In particular, it is a valid HTML page.  </p><h2>  Zope Page Templates versus DTML</h2>
<p>    Zope already has DTML, why do you need another template language.
    First of all, DTML is not aimed at HTML designers.  Once a page
    has been converted into a template, it is invalid HTML, making it
    difficult to work with outside of the application.  Secondly, DTML
    suffers from a failure to separate presentation, logic, and
    content (data).  This decreases the scalability of content
    management and website development efforts that use these systems.</p><p>    DTML can do things that Page Templates can't such as dynamically
    generate email messages (Page Templates can only generate HTML and
    XML). So DTML won't go away. However, we do see Page Templates
    taking over almost all HTML/XML presentation work in Zope.</p><h2>  How Page Templates Work</h2>
<p>    Page Templates use the Template Attribute Language (TAL).  TAL
    consists of special tag attributes. For example, a dynamic page
    title might look like this:<pre>      &lt;title tal:content=&quot;here/title&quot;&gt;Page Title&lt;/title&gt;</pre>
</p><p>    The <code>tal:content</code> attribute is a TAL statement.  Since it has an
    XML namespace (the <code>tal:</code> part) most editing tools will not
    complain that they don't understand it, and will not remove it.
    It will not change the structure or appearance of the template
    when loaded into a WYSIWYG editor or a web browser. The name
    <code>content</code> indicates that it will set the content of the <code>title</code>
    tag, and the value "here/title" is an expression providing the
    text to insert into the tag.</p><p>    All TAL statements consist of tag attributes whose name starts
    with <code>tal:</code> and all TAL statements have values associated with
    them. The value of a TAL statement is shown inside quotes.  See
    Appendix C, "Zope Page Templates Reference", for more information
    on TAL.</p><p>    To the HTML designer using a WYSIWYG tool, the dynamic title
    example is perfectly valid HTML, and shows up in their editor
    looking like a title should look like. In other words, Page
    Templates play nicely with editing tools.</p><p>    This example also demonstrates the principle that, "What you see
    is very similar to what you get". When you view the template in an
    editor, the title text will act as a placeholder for the dynamic
    title text.  The template provides an example of how generated
    documents will look.</p><p>    When this template is saved in Zope and viewed by a user, Zope
    turns the dummy content into dynamic content, replacing "Page
    Title" with whatever "here/title" resolves to.  In this case,
    "here/title" resolves to the title of the object to which to the
    template is applied.  This substitution is done dynamically, when
    the template is viewed.</p><p>    There are template statements for replacing entire tags, their
    contents, or just some of their attributes.  You can repeat a tag
    several times or omit it entirely.  You can join parts of several
    templates together, and specify simple error handling.  All of
    these capabilities are used to generate document structures.
    Despite these capabilities, you <strong>can't</strong> create subroutines or
    classes, perform complex flow control, or easily express complex
    algorithms.  For these tasks, you should use Python-based Scripts
    or application components.</p><p>    The Page Template language is deliberately not as powerful and
    general-purpose as it could be.  It is meant to be used inside of
    a framework (such as Zope) in which other objects handle business
    logic and tasks unrelated to page layout.</p><p>    For instance, template language would be useful for rendering an
    invoice page, generating one row for each line item, and inserting
    the description, quantity, price, and so on into the text for each
    row.  It would not be used to create the invoice record in a
    database or to interact with a credit card processing facility.</p><h2>  Creating a Page Template</h2>
<p>    If you design pages, you will probably use FTP or WebDAV instead
    of the Zope Management Interface (ZMI) to create and edit Page
    Templates. See the "Using FTP and WebDAV" section later in this
    chapter for information on editing Page Templates remotely.  For
    the small examples in this chapter, it is easier to use the ZMI.</p><p>    Use your web browser to log into the Zope Management Interface as
    a manager.  Choose a Folder to work in (the root is fine) and pick
    "Page Template" from the drop-down add list.  Type "simple_page"
    in the add form's <em>Id</em> field, then push the "Add and Edit" button.</p><p>    You should now see the main editing page for the new Page
    Template.  The title is blank, the content-type is <code>text/html</code>,
    and the default template text is in the editing area.</p><p>    Now let's create simple dynamic page. Type the words "a Simple
    Page" in the <em>Title</em> field.  Then, edit the template text to look
    like this:<pre>      &lt;html&gt;
       &lt;body&gt;
         &lt;p&gt;
           This is &lt;b tal:replace=&quot;template/title&quot;&gt;the Title&lt;/b&gt;.
         &lt;/p&gt;
       &lt;/body&gt;
      &lt;/html&gt;</pre>
</p><p>    Now push the <em>Save Changes</em> button.  Zope should show a message
    confirming that your changes have been saved. </p><p>    If an HTML comment starting with <code>&lt;-- Page Template Diagnostics</code>
    is added to the template text, then check to make sure you typed
    the example correctly and save it again. This comment is an error
    message telling you that something is wrong. You don't need to
    erase the error comment; once the error is corrected it will go
    away.</p><p>    Click on the <em>Test</em> tab.  You should see a page with, "This is a
    Simple Page." at the top. Notice that the text is plain; nothing
    is in bold.</p><p>    Back up, then click on the <em>Browse HTML source</em> link under the
    content-type field.  This will show you the <em>unrendered</em> source of
    the template.  You should see, "This is <strong>the Title</strong>."  Back up
    again, so that you are ready to edit the example further.</p><p>    The <em>Content-Type</em> field allows you to specify the content type of
    your page. Generally you'll use a content type of <code>text/html</code> HTML
    or <code>text/xml</code> for XML. </p><p>    If you set the content-type to <code>text/html</code> then Zope parses your
    template using HTML compatiblity mode which allowers HTML's loose
    markup. If you set your content-type to something other than
    <code>text/html</code> then Zope assumes that your template is well formed
    XML. Zope also requires an explicit TAL and METAL XML namespace
    declarations for well formed XML.</p><p>    The <em>Expand macros with editing</em> control is explain in Chapter 9,
    "Advanced Page Templates".</p><h2>  Simple Expressions</h2>
<p>    The expression, "template/title" in your simple Page Template is a
    <em>path expression</em>.  This the most common type of expression. There
    are several other types of expressions defined by the TAL
    Expression Syntax (TALES) standard. For more information on TALES
    see Appendix C, "Zope Page Templates Reference".</p><p>    The "template/title" path expression fetches the <code>title</code> property
    of the template.  Here are some other common path expressions:<ul>
<li><code>request/URL</code>: The URL of the current web request.</li>
<li><code>user/getUserName</code>: The authenticated user's login name.</li>
<li><code>container/objectIds</code>: A list of Ids of the objects in the
      same Folder as the template.</li>
</ul>
</p><p>    Every path starts with a variable name. If the variable contains
    the value you want, you stop there.  Otherwise, you add a slash
    ('/') and the name of a sub-object or property.  You may need to
    work your way through several sub-objects to get to the value
    you're looking for. </p><p>    Zope defines a small set of built-in variables such as <code>request</code>
    and <code>user</code>, which are described in Chapter 9, "Advanced Page
    Templates". You will also learn how to define your own variables
    in that chapter.</p><h2>  Inserting Text</h2>
<p>    In your "simple_page" template, you used the <code>tal:replace</code>
    statement on a bold tag.  When you tested it, Zope replaced the
    entire tag with the title of the template. When you browsed the
    source, you saw the template text in bold. We used a bold tag in
    order to highlight the difference.</p><p>    In order to place dynamic text inside of other text, you typically
    use <code>tal:replace</code> on a <code>span</code> tag rather than on a bold tag.  For
    example, add the following lines to your example:<pre>      &lt;br&gt;
      The URL is &lt;span tal:replace=&quot;request/URL&quot;&gt;URL&lt;/span&gt;.</pre>
</p><p>    The <code>span</code> tag is structural, not visual, so this looks like "The
    URL is URL." when you view the source in an editor or browser.
    When you view the rendered version, it may look something like:<pre>      &lt;br&gt;
      The URL is http://localhost:8080/simple_page.</pre>
</p><p>    If you want to insert text into a tag but leave the tag itself
    alone, you use the <code>tal:content</code> statement.  To set the title of
    your example page to the template's title property, add the
    following lines between the <code>html</code> and the <code>body</code> tags:<pre>      &lt;head&gt;
        &lt;title tal:content=&quot;template/title&quot;&gt;The Title&lt;/title&gt;
      &lt;/head&gt;</pre>
</p><p>    If you open the "Test" tab in a new browser window, the window's
    title will be "a Simple Page". If you view the source of the page
    you'll see something like this:<pre>      &lt;html&gt;
        &lt;head&gt;
          &lt;title&gt;a Simple Page&lt;/title&gt;
        &lt;/head&gt;
      ...</pre>
</p><p>    Zope inserted the title of your template into the <code>title</code> tag. </p><h2>  Repeating Structures</h2>
<p>    Now let's add some context to your page, in the form of a list of
    the objects that are in the same Folder as the template.  You will
    make a table that has a numbered row for each object, and columns
    for the id, meta-type, and title.  Add these lines to the bottom
    of your example template:<pre>      &lt;table border=&quot;1&quot; width=&quot;100%&quot;&gt;
        &lt;tr&gt;
          &lt;th&gt;Number&lt;/th&gt;
          &lt;th&gt;Id&lt;/th&gt;
          &lt;th&gt;Meta-Type&lt;/th&gt;
          &lt;th&gt;Title&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr tal:repeat=&quot;item container/objectValues&quot;&gt;
          &lt;td tal:content=&quot;repeat/item/number&quot;&gt;#&lt;/td&gt;
          &lt;td tal:content=&quot;item/getId&quot;&gt;Id&lt;/td&gt;
          &lt;td tal:content=&quot;item/meta_type&quot;&gt;Meta-Type&lt;/td&gt;
          &lt;td tal:content=&quot;item/title&quot;&gt;Title&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;</pre>
</p><p>    The <code>tal:repeat</code> statement on the table row means "repeat this row
    for each item in my container's list of object values".  The
    repeat statement puts the objects from the list into the <code>item</code>
    variable one at a time (this is called the <em>repeat variable</em>), and
    makes a copy of the row using that variable.  The value of
    "item/getId" in each row is the Id of the object for that row, and
    likewise with "item/meta_type" and "item/title".</p><p>    You can use any name you like for the repeat variable ("item" is
    only an example), as long as it starts with a letter and contains
    only letters, numbers, and underscores ('_').  The repeat variable
    is only defined in the repeat tag. If you try to use it above or
    below the <code>tr</code> tag you will get an error.</p><p>    You can also use the repeat variable name to get information about
    the current repetition.  By placing it after the built-in variable
    <code>repeat</code> in a path, you can access the repetition count from zero
    ('index'), from one ('number'), from "A" ('Letter'), and in
    several other ways. So, the expression <code>repeat/item/number</code> is <code>1</code>
    in the first row, <code>2</code> in the second row, and so on.</p><p>    Since one <code>tal:repeat</code> loop can be placed inside of another, more
    than one can be active at the same time.  This is why you must
    write <code>repeat/item/number</code> instead of just <code>repeat/number</code>. You
    must specify which loop your interested in by including the loop
    name.</p><p>    Now view the page and notice how it lists all the objects in the
    same folder as the template. Try adding or deleting objects from
    the folder and notice how the page reflects these changes.</p><h2>  Conditional Elements</h2>
<p>    Using Page Templates you can dynamically query your environment
    and selectively insert text depending on conditions. For example,
    you could display special information in response to a cookie:<pre>      &lt;p tal:condition=&quot;request/cookies/verbose | nothing&quot;&gt;
        Here's the extra information you requested.
      &lt;/p&gt;</pre>
</p><p>    This paragraph will be included in the output only if there is a
    <code>verbose</code> cookie set. The expression, 'request/cookies/verbose |
    nothing' is true only when there is a cookie named <code>verbose</code>
    set. You'll learn more about this kind of expression in Chapter 9,
    "Advanced Page Templates".</p><p>    Using the <code>tal:condition</code> statement you can check all kinds of
    conditions.  A <code>tal:condition</code> statement does nothing if its
    expression has a true value, but removes the entire statement tag,
    including its contents, if the value is false. Zope considers the
    number zero, a blank string, an empty list, and the built-in
    variable <code>nothing</code> to be false values.  Nearly every other value
    is true, including non-zero numbers, and strings with anything in
    them (even spaces!).</p><p>    Another common use of conditions is to test a sequence to see if
    it is empty before looping over it. For example is the last
    section you saw how to draw a table by iterating over a collection
    of objects. Here's how to add a check to page so that if the list
    of objects is empty no table is drawn:<pre>      &lt;table tal:condition=&quot;container/objectValues&quot; 
             border=&quot;1&quot; width=&quot;100%&quot;&gt;
        &lt;tr&gt;
          &lt;th&gt;Number&lt;/th&gt;
          &lt;th&gt;Id&lt;/th&gt;
          &lt;th&gt;Meta-Type&lt;/th&gt;
          &lt;th&gt;Title&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr tal:repeat=&quot;item container/objectValues&quot;&gt;
          &lt;td tal:content=&quot;repeat/item/number&quot;&gt;#&lt;/td&gt;
          &lt;td tal:content=&quot;item/getId&quot;&gt;Id&lt;/td&gt;
          &lt;td tal:content=&quot;item/meta_type&quot;&gt;Meta-Type&lt;/td&gt;
          &lt;td tal:content=&quot;item/title&quot;&gt;Title&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;</pre>
</p><p>    If the expressions, <code>container/objectValues</code> is false then the
    entire table is omitted.</p><h2>  Changing Attributes</h2>
<p>    Most, if not all, of the objects listed by your template have an
    <code>icon</code> property, that contains the path to the icon for that kind
    of object.  In order to show this icon in the meta-type column,
    you will need to insert this path into the <code>src</code> attribute of an
    <code>img</code> tag.  Edit the meta-type column in both rows to look like
    this:<pre>      &lt;td&gt;&lt;img src=&quot;/misc_/OFSP/Folder_icon.gif&quot;
               tal:attributes=&quot;src item/icon&quot;&gt;
          &lt;span tal:replace=&quot;item/meta_type&quot;&gt;Meta-Type&lt;/span&gt;
      &lt;/td&gt;</pre>
</p><p>    The <code>tal:attributes</code> statement replaces the <code>src</code> attribute of the
    <code>img</code> tag with the value of <code>item/icon</code>.  The
    <code>src=&quot;/misc_/OFSP/Folder_icon.gif&quot;</code> attribute in the template acts
    as a placeholder.</p><p>    Notice that we've replaced the <code>tal:content</code> attribute on the
    table cell with a tal:replace statement on a <code>span</code> tag. This
    change allows you to have both an image and text in the table
    cell.</p><h2>  Creating a File Library with Page Templates</h2>
<p>    Here's an example of using Page Templates with Zope to create a
    simple file library with one template, a little bit of Python
    code, and some files.</p><p>    First, create a mock up of a file library page using your HTML
    editor.  The examples in this chapter were made with
    <a href="http://www.w3.org/Amaya/">Amaya</a>.  This mock-up doesn't need to
    overdo it, it just shows some dummy information.  Here's a mock-up
    of a file library that contains one file:<pre>      &lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;
                            &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;
      &lt;html&gt;
      &lt;head&gt;
        &lt;title&gt;File Library&lt;/title&gt;
        &lt;style type=&quot;text/css&quot;&gt;
        .header {
          font-weight: bold;
          font-family: helvetica;
          background: #DDDDDD;
        }
        h1 {
          font-family: helvetica;
        }
        .filename {
          font-family: courier
        }
        &lt;/style&gt;
        &lt;meta name=&quot;GENERATOR&quot; content=&quot;amaya 5.1&quot;&gt;
      &lt;/head&gt;

      &lt;body&gt;
      &lt;h1&gt;File Library&lt;/h1&gt;

      &lt;p&gt;Click on a file below to download it.&lt;/p&gt;

      &lt;table border=&quot;1&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot;&gt;
        &lt;tbody&gt;
          &lt;tr&gt;
            &lt;td class=&quot;header&quot;&gt;Name&lt;/td&gt;
            &lt;td class=&quot;header&quot;&gt;Type&lt;/td&gt;
            &lt;td class=&quot;header&quot;&gt;Size&lt;/td&gt;
            &lt;td class=&quot;header&quot;&gt;Last Modified&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;td&gt;&lt;a href=&quot;Sample.tgz&quot; class=&quot;filename&quot;&gt;Sample.tgz&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;application/x-gzip-compressed&lt;/td&gt;
            &lt;td&gt;22 K&lt;/td&gt;
            &lt;td&gt;2001/09/17&lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;
      &lt;/body&gt;
      &lt;/html&gt;</pre>
</p><p>    Now, log into your Zope and create a folder called <code>FileLib</code>.  In
    this folder, create a Page Template called <code>index_html</code> by
    selecting <code>Page Template</code> from the add menu, specifying the Id
    <code>index_html</code> in the form, and clicking <em>Add</em>.</p><p>    Now, with your HTML editor, save the above HTML to the URL of the
    <code>index_html</code> Page Template followed by <code>/source.html</code>, for
    example, <code>http://localhost:8080/FileLib/index_html/source.html</code>.
    Notice that the URL to <em>save</em> the <code>index_html</code> page ends in
    <code>source.html</code>.  Because Page Templates are dynamic, you need a way
    to edit the raw source of the template, unrendered by the page
    template language.  Appending <code>source.html</code> to a Page Template
    gives you this raw source. Note, if the content-type of your page
    is <code>text/xml</code> then you'll use <code>source.xml</code>, rather than
    <code>source.html</code>.</p><p>    Now that you've saved the template, you can go back to Zope and
    click on <code>index_html</code> and then click on its <em>Test</em> tab to view the
    template.  It looks just like it the mock-up, so everything is
    going well.</p><p>    Now let's tweak the above HTML and add some dynamic magic.  First,
    we want the title of the template to be dynamic.  In Zope, you'll
    notice that the Page Template has a <em>title</em> form field that you
    can fill in.  Instead of being static HTML, we want Zope to
    dynamically insert the Page Templates title into the rendered
    version of the template.  Here's how:<pre>      &lt;head&gt;
        ...
        &lt;title tal:content=&quot;template/title&quot;&gt;File Library&lt;/title&gt;
        ...

      &lt;body&gt;
      &lt;h1 tal:content=&quot;template/title&quot;&gt;File Library&lt;/h1&gt;
      ...</pre>
</p><p>    Now go to Zope and change the title of the <code>index_html</code> page
    template.  After saving that change, click the <em>Test</em> tab.  As you
    can see, the Page Template dynamically inserted the title of the
    template object in the output of the template.</p><p>    Notice the new <code>content</code> tag attribute in the <code>tal</code> xml namespace.
    This attribute says to "replace the <em>content</em> of this tag with the
    variable 'template/title'".  In this case, <code>template/title</code> is the
    title of the <code>index_html</code> Page Template.</p><p>    The next bit of magic is to build a dynamic file list that shows
    you all the File objects in the <code>FileLib</code> folder.</p><p>    To start, you need to write just one line of Python.  Go to the
    <code>FileLib</code> folder and create a <code>Script (Python)</code> in that folder.
    Give the script the id <code>files</code> and click <em>Add and Edit</em>.  Edit the
    script to contain the following Python code:<pre>      ## Script (Python) &quot;files&quot;
      ## 
      return container.objectValues('File')</pre>
</p><p>    This will return a list of any File objects in the FileLib folder.
    Now, edit your <code>index_html</code> Page Template and add some more <code>tal</code>
    attributes to your mock-up:<pre>      ...
      &lt;tr tal:repeat=&quot;item container/files&quot;&gt;
        &lt;td&gt;&lt;a href=&quot;Sample.tgz&quot; class=&quot;filename&quot;
               tal:attributes=&quot;href item/getId&quot;
               tal:content=&quot;item/getId&quot;&gt;Sample.tgz&lt;/a&gt;&lt;/td&gt;
        &lt;td tal:content=&quot;item/content_type&quot;&gt;application/x-gzip-compressed&lt;/td&gt;
        &lt;td tal:content=&quot;item/getSize&quot;&gt;22 K&lt;/td&gt;
        &lt;td tal:content=&quot;item/bobobase_modification_time&quot;&gt;2001/09/17&lt;/td&gt;
      &lt;/tr&gt;
      ...</pre>
</p><p>    The interesting part is the <code>tal:repeat</code> attribute on the <code>tr</code>
    HTML tag.  This attribute tells the template to iterate over the
    values returned by "container/files" (the Python script you
    created) and create a new table row for each of those files.
    During each iteration, the current file object being iterated over
    is assigned the name <code>item</code>.</p><p>    The cells of each row all have <code>tal:content</code> attributes that
    describe the the data that should go in each cell.  During each
    iteration through the table row loop, the id, the content type,
    the size, and modification times replace the dummy data in the
    rows. Also notice how the anchor link dynamically points to the
    current file using <code>tal:attributes</code> to rewrite the <code>href</code>
    attribute.</p><p>    This data comes from the <code>item</code> object by calling Zope API methods
    on what we know is a file object.  The methods <code>item/getId</code>,
    <code>item/content_type</code>, <code>item/getSize</code>,
    <code>item/bobobase_modification_time</code> are all standard API functions
    that are documented in Zope's online help system.</p><p>    Go to Zope and test this script by first uploading some Files into
    the <code>FileLib</code> folder.  This is done by selecting <code>File</code> from the add
    menu and clicking on the <code>upload</code> form button on the next screen.
    After uploading your file, you can just click <em>Add</em>.  If you do not
    specify an id, then the filename of the file you are uploading will
    be used.</p><p>    After uploading some files, go to the <code>index_html</code> Page Template and
    click the <em>Test</em> tab.  Now, you can see the Page Template has
    rendered a very simple file library with just a few HTML tag
    attribute changes.</p><p>    There are a few cosmetic problems with the file library as it
    stands. The size and date displays are not very pretty and don't
    match the format of the dummy content. You would like the size of
    the files to be displayed in K or MB rather than bytes. Here's a
    Python-based script that you can use for this:<pre>      ## Script (Python) &quot;file_size&quot;
      ##
      &quot;&quot;&quot;
      Return a string describing the size of a file.
      &quot;&quot;&quot;
      bytes=context.getSize()
      k=bytes/1024.0
      mb=bytes/1048576.0
      if mb &gt; 1:
          return &quot;%.2f MB&quot; % mb
      if k &gt; 1:
          return &quot;%d K&quot; % k
      return &quot;%d bytes&quot; % bytes</pre>
</p><p>    Create this script with the Id <code>file_size</code> in your <code>FileLib</code>
    folder. It calculates a file's size in kilobytes and megabytes and
    returns an appropriate string describing the size of the file. Now
    you can use the script in place of the <code>item/getSize</code> expression:<pre>      ...
      &lt;td tal:content=&quot;item/file_size&quot;&gt;22 K&lt;/td&gt;
      ...</pre>
</p><p>    You can also fix the date formatting problems with a little
    Python. Create a script named <code>file_date</code> in your <code>FileLib</code>
    folder:<pre>      ## Script (Python) &quot;file_date&quot;
      ##
      &quot;&quot;&quot;
      Return modification date as string YYYY/MM/DD
      &quot;&quot;&quot;
      date=context.bobobase_modification_time()
      return &quot;%s/%s/%s&quot; % (date.year(), date.mm(), date.day())</pre>
</p><p>    Now replace the <code>item/bobobase_modification_time</code> expression with
    a reference to this script:<pre>      ...
      &lt;td tal:content=&quot;item/file_date&quot;&gt;2001/09/17&lt;/td&gt;
      ...</pre>
</p><p>    Congratulations, you've successfully taken a mock-up and turned it
    into a dynamic Page Template.  This example illustrates how Page
    Templates work well as the "presentation layer" to your
    applications.  The Page Templates present the application logic
    (the Python-based scripts) and the application logic works with the data
    in your site (the files).</p><h2>  Remote Editing with FTP and WebDAV</h2>
<p>    You can edit Page Templates remotely with FTP and WebDAV, as well
    as HTTP PUT publishing.  Using these methods, you can use Page
    Templates without leaving advanced WYSIWYG editors such as
    DreamWeaver. </p><p>    The previous section showed you how to edit a page remotely using
    Amaya, which uses HTTP PUT to upload pages. You can do the same
    thing with FTP and WebDAV using the same steps.<ol>
<li> Create a Page Template in the Zope Management interface. You
      can name it with whatever file extension you wish. Many folks
      prefer <code>.html</code>, while others prefer <code>.zpt</code>. Note, some names
      such as <code>index_html</code> have special meanings to Zope.</li>
<li> Retrieve the file using the URL of you page template plus
      <code>/source.html</code> or <code>/source.xml</code>. This gives you the source of
      your Page Template.</li>
<li> Edit your file with your editor and then save it. When you
      save it you should use the same source URL you used to retrieve
      it.</li>
<li> Optionally reload your page after you edit it, to check for
      error comments. See the next section for more details on
      debugging.</li>
</ol>
</p><p>    In later versions of Zope you'll probably be able to create Page
    Templates without using the Zope Management Interface.</p><h2>  Debugging and Testing</h2>
<p>    Zope helps you find and correct problems in your Page
    Templates. Zope notices problem at two different times: when
    you're editing a Page Template, and when you're viewing a Page
    Template. Zope catches different types of problems when you're
    editing than when you're viewing a Page Template.</p><p>    You're probably already familiar with trouble-shooting comments
    that Zope inserts into your Page Templates when it runs into
    problems. These comments tell you about problems that Zope finds
    while you're editing your templates. The sorts of problems that
    Zope finds when you're editing are mostly errors in your <code>tal</code>
    statements. For example:<pre>      &lt;!-- Page Template Diagnostics
       Compilation failed
       TAL.TALDefs.TALError: bad TAL attribute: 'contents', at line 10, column 1
      --&gt;</pre>
</p><p>    This diagnostic message lets you know that you mistakenly used
    <code>tal:contents</code> rather than <code>tal:content</code> on line 10 of your
    template. Other diagnostic messages will tell you about problems
    with your template expressions and macros.</p><p>    When you're using the Zope management interface to edit Page
    Templates it's easy to spot these diagnostic messages. However, if
    you're using WebDAV or FTP it's easy to miss these messages. For
    example, if you save a template to Zope with FTP, you won't get an
    FTP error telling you about the problem. In fact, you'll have to
    reload the template from Zope to see the diagnostic message. When
    using FTP and WebDAV it's a good idea to reload templates after
    you edit them to make sure that they don't contain diagnostic
    messages.</p><p>    If you don't notice the diagnostic message and try to render a
    template with problems you'll see a message like this:<pre>      Error Type: RuntimeError
      Error Value: Page Template hello.html has errors.</pre>
</p><p>    That's your signal to reload the template and check out the
    diagnostic message.</p><p>    In addition to diagnostic messages when editing, you'll
    occasionally get regular Zope errors when viewing a Page
    Template. These problems are usually due to problems in your
    template expressions. For example, you might get an error if an
    expression can't locate a variable:<pre>      Error Type: Undefined
      Error Value: &quot;unicorn&quot; not found in &quot;here/unicorn&quot;</pre>
</p><p>    This error message tells you that it cannot find the <code>unicorn</code>
    variable which is referenced in the expression, <code>here/unicorn</code>. To
    help you figure out what went wrong, Zope includes information
    about the environment in the traceback. If you're in debugging
    mode this information will be available at the bottom of the error
    page. Otherwise, view the source of the error page to see the
    traceback. The traceback will include information about the
    environment:<pre>      ...
      'here': &lt;Application instance at 01736F78&gt;,
      'modules': &lt;Products.PageTemplates.ZRPythonExpr._SecureModuleImporter instance at 016E77FC&gt;,
      'nothing': None,
      'options': {'args': ()},
      'request': ...
      'root': &lt;Application instance at 01736F78&gt;,
      'template': &lt;ZopePageTemplate instance at 01732978&gt;,
      'traverse_subpath': [],
      'user': amos})
      ...</pre>
</p><p>    This information is a bit cryptic, but with a little detective
    work it can help you figure out what went wrong. In this case, it
    tells us that the <code>here</code> variable is an "Application
    instance". This means that it is the top-level Zope folder (notice
    how <code>root</code> variable is the same "Application instance"). Perhaps
    the problem is that you wanted to apply the template to a folder
    that had a <code>unicorn</code> property. The traceback doesn't provide a lot
    of help, but it can help you sometimes.</p><h2>  XML Templates</h2>
<p>    Another example of the flexibility of Page Templates is that they
    can dynamically render XML as well as HTML.  For example, in
    Chapter 5, "Creating Basic Zope Applications", you created the
    following XML:<pre>      &lt;guestbook&gt;
        &lt;entry&gt;
          &lt;comments&gt;My comments&lt;/comments&gt;
        &lt;/entry&gt;
        &lt;entry&gt;
          &lt;comments&gt;I like your web page&lt;/comments&gt;
        &lt;/entry&gt;
        &lt;entry&gt;
          &lt;comments&gt;Please no blink tags&lt;/comments&gt;
        &lt;/entry&gt;
      &lt;/guestbook&gt;</pre>
</p><p>    This XML was created by looping over all the DTML Documents in a
    folder and inserting their source into <code>comment</code> elements.  In
    this section, we'll show you how to use Page Templates to generate
    this same XML.</p><p>    Create a new Page Template called "entries.xml" in your guest book
    folder with the following contents:<pre>      &lt;guestbook xmlns:tal=&quot;http://xml.zope.org/namespaces/tal&quot;&gt;
        &lt;entry tal:repeat=&quot;entry python:here.objectValues('DTML Document')&quot;&gt;
          &lt;comments tal:content=&quot;entry/document_src&quot;&gt;Comment goes here...&lt;/comments&gt;
        &lt;/entry&gt;
      &lt;/guestbook&gt;</pre>
</p><p>    Make sure you set the content type to <code>text/xml</code>.  Now, click
    <em>Save Changes</em> and click the <em>Test</em> tab.  If you're using
    Netscape, it will prompt you to download an XML document, if you
    are using MSIE 5 or higher, you will be able to view the XML
    document in the browser.</p><p>    Notice how the <code>tal:repeat</code> statement loops over all the DTML
    Documents. The <code>tal:content</code> statement inserts the source of each
    document into the <code>comments</code> element. The <code>xmlns:tal</code> attribute is
    an XML namespace declaration. It tells Zope that names that start
    with <code>tal</code> are Page Template commands. See Appendix C, "Zope Page
    Templates Reference" for more information about TAL and TALES XML
    namespaces.</p><p>    Creating XML with Page Templates is almost exactly like creating
    HTML. The most important difference is that you must use explicit
    XML namespace declarations.  Another difference is that you should
    set the content type to <code>text/xml</code> or whatever the content-type
    for your XML should be.  The final difference is that you can
    browse the source of an XML template by going to <code>source.xml</code>
    rather than <code>source.html</code>.</p><h2>  Using Templates with Content</h2>
<p>    In general Zope supports content, presentation, and logic
    components. Page Templates are presentation components and they
    can be used to display content components. </p><p>    Zope 2.5 ships with several content components: ZSQL Methods,
    Files, and Images. DTML Documents and methods are not really pure
    content components since they can hold content and execute DTML
    code. As this time Zope doesn't come with a good general purpose
    content object. You can use Files for textual content since you
    can edit the contents of Files if the file is less than 64K and
    contains text. However, the File object is pretty basic.</p><p>    Zope's Content Management Framework (CMF) solves this problem by
    providing an assortment of rich content components.  The CMF is
    Zope's content management add on. It introduces all kinds of
    enhancements including work-flow, skins, and content objects. The
    CMF makes a lot of use of Page Templates. A later release of Zope
    will probably include the CMF.</p><h2>  Conclusion</h2>
<p>    Zope Page Templates help you build web pages for your web
    applications. Templates make it easier for you to use normal HTML
    tools and techniques to build web pages. They also provide
    convenient hooks to allow you to attach them to your
    applications. Page Templates help designers and programmers work
    together to produce web applications.  In Chapter 9, "Advanced
    Page Templates", you'll learn about powerful template techniques
    like Python expressions, and macros.</p></body>
</html>