You are not logged in Log in Join
You are here: Home » Zope Documentation » Books » The Zope Book Releases » The Zope Book (2.6 Edition) » Using Zope Page Templates

Log in
Name

Password

 
Previous Page Up one Level Next Page Using Zope Page Templates Comments On/Off Table of Contents

Using Zope Page Templates

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 features of Page Templates, including how you can use them in your web site to create dynamic web pages easily. In the chapter entitled Advanced Page Templates, you'll learn about advanced Page Template features.

Anonymous User - Sep. 4, 2004 5:54 pm:
 A suggestion for new readers: The topics covered in this chapter are fairly complex. It may help to turn off
 comments the first time and just read the information as presented. Click the button at the top of the page
 labeled "COM ON". The button should change to "COM OFF" and user comments should be removed allowing you to
 read the page without the distraction of third party remarks. Once you've read through the page, you can
 click on the "COM OFF" button to review the comments made by others, which you may or may not find useful in
 understanding this chapter.
A suggestion for the page maintainer: the add comment form or page does not have the "Preview Comment" button
 that is says it should have.

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 back 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.

Page Templates aim at this goal by adopting three principles:

  1. Play nicely with editing tools.
  2. What you see is very similar to what you get.
  3. Keep code out of templates, except for structural logic.

A Page Template is like a model of the pages that it will generate. In particular, it is a valid HTML page.

Anonymous User - Mar. 25, 2004 3:28 pm:
 Zope Page Templates generate validation errors (for example at http://validator.w3.org) because of invalid
 attributes, even when attribute namespaces are declared. How then is a Zope Page Template valid HTML?
Anonymous User - Mar. 26, 2004 7:58 pm:
 It's true that PageTemplates resemble HTML, but they also include TAL, METAL, and TALES statements which are
 only useful to Zope, not web browsers. Remember that PageTemplates are *not* HTML documents, they are
 instructions for Zope that detail how to build HTML documents out of dynamic data.
 You can only validate the HTML in documents that have been rendered from a PageTemplate, you cannot directly
 validate the PageTemplate itself. But the template has to contain valid HTMl, otherwise when it is rendered
 the resulting HTML document won't be valid.
 It not surprising that PageTemplates won't validate, using an HTML validator. They are often incomplete HTML
documents, lacking the neccessary <html>, <head>, and <body> elements for example. When
Zope renders a page
 from a template, it usually draws upon many other dependent templates.
PageTemplates resemble HTML well enough to be rendered by most browsers and visual editors. They are intended
 to make life easier for HTML designers because they can build HTML pages using dummy content, then the
 programmer adds the instructions that replace the dummy with dynamically acquired data. The page design is
 separated, from the logic design, yet both can be easily maintained.
 To understand the philosophy behind Page Templates, see them in action in this <a
 href="http://zope.org/Documentation/Articles/ZPT3">tuttorial</a>.
Anonymous User - Apr. 7, 2004 2:17 pm:
 what the hell is this
Anonymous User - Aug. 5, 2004 12:42 pm:
I believe what the gentleperson who comented on Mar. 25, 2004 @ 3:28pm is attempting to say is that Zope does
not render proper HTML even when it renders the templates. There are numerous validation errors. Point the w3
 validator at any HTML document and it usually finds some. Zope does not generate VALID HTML, but it is
 capable of generating (though very poor) interpretable HTML.
Anonymous User - Dec. 11, 2004 4:21 pm:
 I'm not sure what the anonymous user of Aug. 5th is talking about, but assuming that the author knows what
he's doing, Page Templates can readily output valid, optimized XHTML. It's even fairly simple to make DTML do
 the same, although because Page Templates are themselves valid XML they tend to be easier to validate than
 DTML files...
Perhaps if the supposed validation errors being seen were specifically mentioned, others could help point you
to the source of the problems. Page Templates don't force you to write valid HTML, but they do make it pretty
 easy.
Anonymous User - Mar. 14, 2005 2:21 pm:
 I think it's like this: Page Templates can both /be/ valid XHTML and can /output/ valid XHTML, if they are
 written as such.
- If written correctly and viewed directly (NOT rendered by Zope), they will show the static content that the
 page author included, which may well be valid XHTML.
 - If written correctly and rendered by Zope (and if the dynamic content that is inserted by the tal:
 statements is also written correctly), they will show the dynamic content that the page author intended,
 which may well be valid XHTML.
 The documentation author's intent, I think, was to show that the tal: statements /extend/ valid XHTML tags,
 rather than taking the form of invalid DTML tags.

Zope Page Templates versus DTML

Zope already has DTML, so you may wonder why we need another template language. First of all, DTML is not aimed at HTML designers. Once an HTML page has been "dynamicized" by inserting DTML into it, the resulting page typically becomes invalid HTML, making it difficult to work with outside Zope. 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. Finally, DTML's namespace model adds too much "magic" to object lookup, without allowing enough control.

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 is not a "dead end". However, it is probable that Page Templates will be used for almost all HTML/XML presentation by Zope Corporation and many members of the Zope community.

How Page Templates Work

Page Templates use the Template Attribute Language (TAL). TAL consists of special tag attributes. For example, a dynamic page title might look like this:


<title tal:content="here/title">Page Title</title>

The tal:content attribute is a TAL statement. Since it has an XML namespace (the tal: 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 content indicates that it will set the text contained by the title tag, and the value "here/title" is an expression providing the text to insert into the tag.

Anonymous User - Aug. 22, 2004 10:28 pm:
 Throughout this section, the documentation talks of "tags" when it should really talk about "elements". For
 instance, the "tal:replace" attribute does NOT cause the TAG (which for one thing would not include the
 corresponding end-tag) to be replaced but the ELEMENT. Subtle but important difference.
Anonymous User - Mar. 16, 2005 1:13 pm:
 Please stop banging on about web designers and tell me how these things work!!!

All TAL statements consist of tag attributes whose name starts with tal: 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.

Anonymous User - Feb. 25, 2004 2:48 am:
 How about a link to Appendix C?...
 http://zope.org/Documentation/Books/ZopeBook/2_6Edition/AppendixC.stx

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.

rroslan - Nov. 10, 2004 11:14 am:
 Do you mean 'Page Tittle' would be what the HTML designer sees in a WYSIWYG editor?

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.

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 the template is applied. This substitution is done dynamically, when the template is viewed.

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 can't create subroutines or classes, perform complex flow control, or easily express complex algorithms using a Page Template. For these tasks, you should use Python-based Scripts or application components.

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.

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.

Anonymous User - Nov. 20, 2003 3:45 am:
 I don't think this section is as clear as it could be.

 .............................................

 This is how I think TAL works (based on this tutorial and a few little experiments)

 ..............................................

 TAL markup is always of the form:

 tal:statement="value"

 .............................................

 EXAMPLE

 If you create a plain text file named 'insertme' in the same directory as the Xope Page Template then stick:

 tal:content="here/insertme" into the HTML <scan> tag, like this:

 <scan tal:content="here/insertme">You shoudn't see this</scan>

 Then what you will see once the page has been 'rendered' by Zope is simply the contents of the file
 'insertme'
 .............................................

 1. The 'here' refers to the folder in which the template is located ???

 2. This is how 'content' is kept seperate from 'presentation' ???

 .............................................

 I don't know if this makes anything more or less clear, or is just plain wrong.

 .............................................

 I think that if anybody re-writes this section they should include a few more examples.
Anonymous User - Dec. 2, 2003 11:05 pm:
 You are almost right. 'here' refers to the namespace in which the template is 
 currently being called, not necessarily where it's located. This is a subtle
 (and often irrelevant) distinction which is explained in later chapters.
Anonymous User - Feb. 13, 2004 5:05 pm:
 I hope Anonymous User - Nov. 20, 2003 3:45 am meant the "span" tag and not the "scan" tag, because otherwise
 I'm even more confused than I think I am.
Anonymous User - Apr. 10, 2004 10:28 pm:
 It would be very useful if when a line of program code is typed, that the next entry be typed as the line of
 code were displayed by the web browser. When I see a word, "Table" in a line of code, does it mean taht the
 word is a command, a variable, a word which must match the same word in a look-up matrix or what? If the the
 word, "Title" means and when rendered as a web page will display, "Susan Jones Home Page", then so state in
the line of code. Don't leave me wondering if "title" has some dark, magic meaning, or is simply a short-hand
 place holder which the web page designer will eventually substitute with "Susan Jones Home Page." KISS,
 PLEASE.
 Thanks,
 Jim

Creating a Page Template

If you design pages, you will probably use FTP or WebDAV instead of the Zope Management Interface (ZMI) to edit Page Templates. See the later section in this chapter named "Remote Editing With FTP and WebDAV" for information on editing Page Templates remotely. For the small examples in this chapter, it is easier to use the ZMI.

Anonymous User - Mar. 13, 2005 10:45 pm:
 Giang Huynh

Use your web browser to log into the Zope Management Interface as a manager. Create a Folder to work in named "template_test" in the root of your Zope. Visit this folder and choose "Page Template" from Zope's add list (do NOT choose DTML Method or DTML Document, the following examples only work inside a Page Template). Type "simple_page" in the add form's Id field, then push the "Add and Edit" button.

Anonymous User - Jan. 14, 2005 1:51 pm:
 How this exemple is done in Zope3 ?????
Anonymous User - Aug. 9, 2005 2:43 am:
 yyyyyy

You should now see the main editing page for the new Page Template. The title is blank, the content-type is text/html, and the default template text is in the editing area.

Anonymous User - July 16, 2004 12:33 pm:
 To see trhe main editing page you should click on the "simple_page" link
 Otherwise you will see "template_test" folder content
Anonymous User - Mar. 13, 2005 10:47 pm:
 Thia is a sample

Now let's create a simple dynamic page. Type the words "a Simple Page" in the Title field. Then, edit the template text to look like this:


<html>
 <body>
   <p>
     This is <b tal:replace="template/title">the Title</b>.
   </p>
 </body>
</html>
Anonymous User - Jan. 14, 2005 1:55 pm:
 this tal arguement "template/title" is unknown in zope 3, was it replace by something else ???
Anonymous User - July 30, 2005 8:13 pm:
 MySQL sucks
 MacOS X stinks
 DJBDNS breaks the internet

Now push the Save Changes button. Zope should show a message confirming that your changes have been saved.

If an HTML comment starting with Page Template Diagnostics 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.

Click on the Test 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. This is because the tal:replace statement replaces the entire tag.

Anonymous User - Feb. 4, 2004 5:53 pm:
 Perhaps the tal:contents statement should be introduced first? Showing the user that the data has been
 inserted dynamically is a good first step. Then describing how you can actually replace tag as well as the
 contents seems like a next step to me.
Anonymous User - Feb. 13, 2004 5:19 pm:
 Is tal:contents a typo of tal:content, or are they two different statements?
Anonymous User - Mar. 26, 2004 8:01 pm:
 It's a typo.

Back up, then click on the Browse HTML source link under the content-type field. This will show you the unrendered source of the template. You should see, "This is the Title." The bold text acts as a placeholder for the dynamic title text. Back up again, so that you are ready to edit the example further.

The Content-Type field allows you to specify the content type of your page. Generally you'll use a content type of text/html HTML or text/xml for XML.

If you set the content-type to text/html then Zope parses your template using HTML compatiblity mode which allows HTML's "loose" markup. In this mode, it's possible to enter "non-well-formed" HTML into a Page Template. However, if you set your content-type to something other than text/html then Zope assumes that your template is well formed XML. Zope also requires an explicit TAL and METAL XML namespace declarations in order to emit XML. For example, if you wish to emit XHTML, you might put your namespace declarations on the html tag:


<html xmlns:tal="http://xml.zope.org/namespaces/tal"
  xmlns:metal="http://xml.zope.org/namespaces/metal">
Anonymous User - July 16, 2004 12:48 pm:
"However, if you set your content-type to something other than text/html then Zope assumes that your template
 is well formed XML."
 If you set your content-type to 'image/jpeg' for example, and slick 'Test', you'll get an error "The image
 “your_host/template_test/simple_page” cannot be displayed, because it contains errors."
 So, maybe the proper sentense should be:
 "However, if you set your content-type to text/xml then Zope assumes that your template is well formed XML."
 (which is quite obvious)
golem1 - July 20, 2004 2:26 pm:
 "...if you set your content-type to something other than text/html then Zope assumes that your template is
 well formed XML. Zope also requires an explicit TAL and METAL XML namespace declarations in order to emit
 XML."
 Is it just me, or is there an inconsistency here? We need to know which are necessary conditions and which
 are sufficient conditions to emit XML.

For our purposes, we want to emit "loose" HTML, so we leave the Content-Type form field as text/html and we do not use any XML namespace declarations.

The Expand macros with editing control is explained in the chapter entitled Advanced Page Templates.

Anonymous User - Nov. 4, 2003 10:47 am:
 Creating a Page Template  was the last headline.

 Simple Expressions   is the next one?  How about:

 Understanding TAL Statements       then
   The Structure of TAL Statements   then
   Expressions                       then
     Path Expressions

 It is virtually impossible to penetrate this text.
Anonymous User - Feb. 1, 2004 12:46 am:
 My 2c:

 I have to put in and say that this is not really very useful as an introductory text. It's more like the
 O'Reilly 'in a nutshell' series. It is easy for someone with programming, and particularly templating
 experience, but not for a beginner, which is what it should be aimed at, since it is the core documentation
 for Zope. That said, this manual is still in its formative stages; I'm just agreeing with the need for more
 thorough explanation and partitioning of concepts into sections... Ahh, if only there was time...
Anonymous User - Feb. 25, 2004 5:32 pm:
 # It is virtually impossible to penetrate this text.

 I agree that there is a need for beginner-level documentation, feel free to contribute and write something.
It is F/OSS after all. There's nothing stopping you from fleshing out your outline. Go for it! You could even
 paste a link and maybe somebody will merge it into the text.
 That being said, here's a couple of links to a 4-part ZPT tutorial by Harish Kamath:

 http://www.devshed.com/c/a/Zope/ZPT-Basics-part-1/
 http://www.devshed.com/c/a/Zope/ZPT-Basics-part-2/
 http://www.devshed.com/c/a/Zope/ZPT-Basics-part-3/
 http://www.devshed.com/c/a/Zope/ZPT-Basics-part-4/
Anonymous User - Apr. 4, 2004 3:54 pm:
Perhaps it should be pointed out the in F/OSS, work is motivated by personal need (scratching your own itch).
 As a result, the people who are *able to write* docs for beginners won't care to, and the people who *need*
 docs for beginners can't write them.
Anonymous User - May 12, 2004 1:14 pm:
 It would be nice to have an option while reading this to get rid of all the inane Anonymous User comments
 (including this one) so I can focus on the doument.
Anonymous User - May 23, 2004 4:32 pm:
 Indeed!! Please_
 How do u know, if this document is bad, if u can't read on, browse a couple lines back, etc...?
 Give us that 'kill comments'-button !-)
Anonymous User - June 1, 2004 2:59 pm:
 there is a kill comments button, it looks like:

 COM
 off

 in a square at the top and bottom of every page.

Simple Expressions

The expression, "template/title" in your simple Page Template is a path expression. This the most common type of expression. There are several other types of expressions defined by the TAL Expression Syntax (TALES) specification. For more information on TALES see the Zope Page Templates Reference Appendix.

The "template/title" path expression fetches the

title

property of the template. Here are some other common path expressions:

  • 'request/URL': The URL of the current web request.
  • 'user/getUserName': The authenticated user's login name.
  • 'container/objectIds': A list of Ids of the objects in the same Folder as the template.

Anonymous User - Nov. 4, 2003 10:40 am:
 First, the syntax has not been explained.
 Second, we do not know what an expression is.
 Third, wer are already being confronted with "request", "container" and objectIDs.
 But, we don't know what any of these things mean. The text does not promote learning but confusion and is
 understandable only to those who already know how things work. That does not help the Zope community grow.
 Tom Snell

Anonymous User - July 29, 2004 8:35 am:
 I agree with you!
 Sometimes it's difficult to understand. Because of not knowing, what the variables mean.
 I am also missing larger examples, with descriptions from top to the end of the script, and are really
 running.

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.

Anonymous User - Nov. 20, 2003 4:17 am:
 Newbie confusion:

 Every path starts with a variable name....

 So 'user', 'home', 'here', 'template', 'request' and 'container' are variables? 

 You add a slash (/) and the name of a sub-object or property....

 What is a property? Can you please give me an example of a property?
 Even better. Five examples of properties, how they can be used and why they are cool.

 I've got all these words jumbling around in my head:

 object, value, variable, property, path, expression... the subtle differences in meanings are getting
 smudged....
 My understanding of OOP is that everything is an object and objects consist of data and methods, I suppose
 that sub-objects could be referenced using path notation /rootobject/sub-object/sub-object
 But what is a property?

 Where do properties fit into the jigsaw puzzle?

 I think this tutorial needs a whole subsection on properties.
Anonymous User - Nov. 24, 2003 4:20 pm:
 think of a property as an attribute of the class or container.
 property could be a name, type, category, quantity , size , etc...
Review the object oriented section for further clarification , focus on a property and attribute representing
 the same concept.

Zope defines a small set of built-in variables such as request and user, which are described in the chapter entitled Advanced Page Templates. You will also learn how to define your own variables in that chapter.

Anonymous User - Nov. 20, 2003 4:05 am:
 The example 'path expressions' we've seen so far are:

 here/title
 here/insertme
 template/title
 request/URL
 user/getUserName
 container/ObjectIDs

 Perhaps just a very small introductory discussion of these top-level paths (built in variables ?): 'here',
 'template', 'request', 'user' and 'container' might not go astray... and of course examples, examples,
 examples of how they can be used and why they are cool.
Anonymous User - May 1, 2004 3:52 am:
 Of course, an obvious question is: where's the list of possible "path expressions"? What's the list of
 objects and attributes/properties that they have? I can't find one anywhere, which makes learning TAL a case
 of poring over examples (or even the Python source code) to try and find out. Not good, guys.
 Anyway, here's something that might help: create an external (Python) method in the root folder (I call it
 'dirt') and put the following python script in the Extensions folder of your instance, called 'dirt.py':
 def dirt(self):
   str="Strings\n"
   for x in dir(self):
     if hasattr(self,x):
       y = getattr(self,x)
       if type(y) == type(str):
         str=str+`x`+': "'+y+'"\n'
   str=str+"\nOthers\n"
   for x in dir(self):
     if hasattr(self,x):
       y = getattr(self,x)
       if type(y) != type(str):
         str=str+`x`+'\n'
   return str

 Now, if you add 'dirt' to the end of any Zope URL (even just 'http://myhost/dirt'), you'll get a dump of all
 the attributes of the container object. Strings are shown first, then all the other guff. It's not the
 reference that should be here, but it's helped me.
 Incidentally, if the python code comes out all mucked up, sorry, but there's no 'preview comment' button on
 this form...
 ben_
dturvene - Aug. 3, 2005 4:42 pm:
 ZPT path expressions are highly context sensitive so I'm not surprised there is little documentation. I find
 the quickest way to analyze an unknown Zope class/AT/widget/etc is to create a simple external script that
 calls pdb.set_trace(). This drops the Zope session into the Python PDB at the point of the script call and
 all structures are available for perusal. Also, most methods can be invoked. Here's the script:
 def settrace(self, obj):
     '''Set a PDB trace
       Invoke in a ZPT using:
       "python: context.settrace(<obj>)"
     '''
     print '%s - %s' % ('settrace', time.asctime())
     pdb.set_trace()
     return 'settrace exitting'

 Here's an example of how to invoke it from ZPT where I want to inspect the properties of the current AT
 widget class:
  <div tal:content="python: context.settrace(widget)">Repl</div>

 Note that both the external script and the ZPT script can be modified and re-run when the HTML page is
 refreshed (Ctl-R in Firefox.)
As an aside, a quick way to fix/populate content is through this (calling the appropriate AT accessor/mutator
 methods) and then calling get_transaction().commit() to save the changes persistently to ZODB.
Oh, and one more thing while I'm here about ATs. The Schema (self.schema) has a LOT of information about AT.
Dumping
 the Schema is a lot more valuable than dumping all the methods for the instance.
 Dave

Inserting Text

In your "simple_page" template, you used the tal:replace 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.

In order to place dynamic text inside of other text, you typically use tal:replace on a span tag rather than on a bold tag. For example, add the following lines to your example:


<br>
The URL is <span tal:replace="request/URL">http://www.example.com</span>.

The span tag is structural, not visual, so this looks like "The URL is http://www.example.com." when you view the source in an editor or browser. When you view the rendered version, however, it may look something like:


The URL is http://localhost:8080/template_test/simple_page.

If you want to insert text into a tag but leave the tag itself alone, you use the tal:content statement. To set the title of your example page to the template's title property, add the following lines between the html and the body tags:


<head>
  <title tal:content="template/title">The Title</title>
</head>

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:


<html>
  <head>
    <title>a Simple Page</title>
  </head>
...
Anonymous User - July 16, 2004 1:15 pm:
 Second sentence should be:
 "If you view the source of the Workspace Frame you'll see something like this:"
Anonymous User - July 27, 2004 4:40 am:
 No it shouldn't.

 Source of workspace frame:

 <head>
   <title tal:content="template/title">The Title</title>
 </head>

 Source of the page (after rendered and served by zope):

 <head>
     <title>a Simple Page</title>
 </head>

 See the difference?

Zope inserted the title of your template into the title tag.

Repeating Structures

Now let's add some context to your simple_page template, 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:


<table border="1" width="100%">
  <tr>
    <th>Number</th>
    <th>Id</th>
    <th>Meta-Type</th>
    <th>Title</th>
  </tr>
  <tr tal:repeat="item container/objectValues">
    <td tal:content="repeat/item/number">#</td>
    <td tal:content="item/getId">Id</td>
    <td tal:content="item/meta_type">Meta-Type</td>
    <td tal:content="item/title">Title</td>
  </tr>
</table>
Anonymous User - Dec. 22, 2003 11:01 am:
 ERROR! should read "td tal:content="item/number">#</td>
Anonymous User - Dec. 27, 2003 12:33 am:
 No, actually it should read exactly what it says there.
 The explanation for why it should have the "repeat/" before it is quite bad, though.
Anonymous User - Dec. 27, 2003 1:04 am:
 Nevermind, it makes sense now:
 'repeat' is a variable.
 no object in the 'item' array has a 'number' attribute
 so to number everything, you need to write 'repeat/number' to get the 'repeat' variable's 'number attribute'

 since the tal:repeat may be nested, 'repeat/number' is ambigious in this context, so:
 'repeat/list/number'

 makes sense now :)
Anonymous User - Feb. 1, 2004 2:37 am:
 Yes, it does make sense if you pay attention and read below. I think that the explanation is quite
 reasonable, but the distinction between "repeat/item/number" being a reference to the repetition number, and
 the "item/getId" being a reference to an attribute of the item in question is not immediately clear. If you
 think about it, it is, but a clear statement of the distinction would be useful.
 Incidentally, an example of a nested loop may have cleared this up a little by encouraging a little bit of
 intuitive learning.
Anonymous User - Mar. 4, 2004 4:04 am:
 horrible syntax :-\
Anonymous User - Mar. 26, 2004 7:19 am:
 What do you do if you have an SQL join and want to display both to the screen 

 e.g.

 Two Tables - one called users one called items

 a query that matches the id of someone who made an item vs the id and username in the user table. I cant do
 <div tal:repeat="items user here/blah/method_thing"></div>
Anonymous User - Apr. 19, 2004 1:40 am:
 The syntax used for the repeat reminds me of xslt, which makes sense in this context. Not that i love the
 syntax, either :-\
Anonymous User - July 27, 2004 3:30 pm:
 item/getID generates an error. It should read item/id, which works.

The tal:repeat 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 item variable one at a time (this is called the repeat variable), 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".

Anonymous User - Apr. 4, 2004 4:08 pm:
Suppose you just want to repeat <p>BOOGER</p> five times. By the end of this section we still
don't know how
 to do that.

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 tr tag you will get an error.

Anonymous User - July 27, 2004 3:36 pm:
 I believe "The repeat variable is only defined in the repeat tag." should read "The repeat variable is only
 defined in the tr tag." Or, since I'm new to the syntax, it should read "The repeat variable is only defined
 in the repeat expression.".

You can also use the repeat variable name to get information about the current repetition. By placing it after the built-in variable repeat 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 repeat/item/number is 1 in the first row, 2 in the second row, and so on.

Since a tal:repeat loop can be placed inside of another, more than one can be active at the same time. This is why you must write repeat/item/number instead of just repeat/number. You must specify which loop you're interested in by including the loop name.

Anonymous User - Feb. 2, 2004 11:51 pm:
 Some confusion here comes from the distinction between paths in file namespace and paths in class namespace.

 It should be stated that the toplevel 'path' specified (ie, "repeat") is actually a base class instance
 created, not a place or random variable. The "this object was created by this statement, now we use this
 property of this object" sentence would be nice.
Anonymous User - Mar. 23, 2004 6:12 am:
 Anonymous writers should be restricted. The pages are becoming longer than required.
Anonymous User - May 30, 2004 9:29 pm:
If you don't want to read the comments, just click the little "COM Off" box at the top of this page to toggle
 comments off.

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.

Conditional Elements

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:


<p tal:condition="request/cookies/verbose | nothing">
  Here's the extra information you requested.
</p>

This paragraph will be included in the output only if there is a verbose cookie set. The expression, request/cookies/verbose | nothing is true only when there is a cookie named verbose set. You'll learn more about this kind of expression in the chapter entitled Advanced Page Templates.

Using the tal:condition statement you can check all kinds of conditions. A tal:condition statement leaves the tag and its contents in place if its expression has a true value, but removes them if the value is false. Zope considers the number zero, a blank string, an empty list, and the built-in variable nothing to be false values. Nearly every other value is true, including non-zero numbers, and strings with anything in them (even spaces!).

Another common use of conditions is to test a sequence to see if it is empty before looping over it. For example in 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 the page so that if the list of objects is empty no table is drawn. Add this to the end of your simple_page Page Template:


<table tal:condition="container/objectValues" 
       border="1" width="100%">
  <tr>
    <th>Number</th>
    <th>Id</th>
    <th>Meta-Type</th>
    <th>Title</th>
  </tr>
  <tr tal:repeat="item container/objectValues">
    <td tal:content="repeat/item/number">#</td>
    <td tal:content="item/getId">Id</td>
    <td tal:content="item/meta_type">Meta-Type</td>
    <td tal:content="item/title">Title</td>
  </tr>
</table>

Go and add three Folders named "1", "2", and "3" to the "template_test" folder in which your simple_page template lives. Revisit the simple_page template and view the rendered output via the Test tab. You will see a table that looks much like the below:


Number          Id          Meta-Type          Title
1               simple_page Page Template
2               1           Folder
3               2           Folder
4               3           Folder

Note that if the expressions, container/objectValues is false (for instance if there are no objectValues), the entire table is omitted.

Anonymous User - July 14, 2004 8:18 pm:
 Seems like the example could benefit from an illustration of where the table would actually be omitted.
 Otherwise, the result is the same as the earlier representation.
Anonymous User - Sep. 5, 2004 7:14 pm:
 It seems to me that the expression as written will never evaluate to false because there is always at least
 one object in the container, simple_page itself. The table will be omitted if the template is modified as
 follows and the page is invoked from one of the empty folders
 (http://localhost:8080/template_test/1/simple_page)
 <table tal:condition="here/objectValues" 
        border="1" width="100%">
   <tr>
     <th>Number</th>
     <th>Id</th>
     <th>Meta-Type</th>
     <th>Title</th>
   </tr>
   <tr tal:repeat="item here/objectValues">
     <td tal:content="repeat/item/number">#</td>
     <td tal:content="item/getId">Id</td>
     <td tal:content="item/meta_type">Meta-Type</td>
     <td tal:content="item/title">Title</td>
   </tr>
 </table>

 Note the change to here/objectValues from container/objectValues

 ~Juan

Changing Attributes

Most, if not all, of the objects listed by your template have an icon 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 src attribute of an img tag. Edit the table cell in the meta-type column of the above example to look like this:


<td><img src="/misc_/OFSP/Folder_icon.gif"
         tal:attributes="src item/icon">
    <span tal:replace="item/meta_type">Meta-Type</span>
</td>
Anonymous User - July 18, 2004 11:27 pm:
 This is driving me ----CRAAAAAAZZZYY----
 I'm trying to use tal:attributes to specify the src for an image (which is a Zope object), and also specify
 300 for the width in the image tag.. Like this:
           <img src="none" tal:attributes="src container/tbox_top_span" width="300" />

And lo and behold, it stringifies the tbox_top_span into an img tag, but uses &lt; and other HTML
entities
 instead of the real thing; with tal:replace and tal:content, there is a 'structure' keyword to get around
 this; how can I just specify that I want to replace the src attribute of the img tag with the physical
 filename of the image??
Anonymous User - Sep. 5, 2004 7:39 pm:
I think the problem is that container/tbox_top_span is evaluated to an actual image not the name as a string.
 If you are not dynamically determining the image name you don't need the attribute clause. You can simply
 write it as:
 <img src="tbox_top_span" width="300">

 And if you determine the name dynamically you probably have a variable that evaluates to the name of the
 image as a string. That's what you should pass to the attribute call.
 I'm new to zope so I could be wrong.

 ~Juan
Anonymous User - Sep. 5, 2004 8:10 pm:
 Oh...  after reading a bit down I realized that you can do the following:

 <img src="none" tal:attributes="src container/tbox_top_span/getId" width="300">

 That's probably what you were trying to do

 ~Juan

The tal:attributes statement replaces the src attribute of the img tag with the value of item/icon. The src="/misc_/OFSP/Folder_icon.gif" attribute in the template acts as a placeholder.

Notice that we've replaced the tal:content attribute on the table cell with a tal:replace statement on a span tag. This change allows you to have both an image and text in the table cell.

Creating a File Library with Page Templates

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.

First, create a "temporary" mock up of a file library page using an HTML "WYSIWYG" ("What You See Is What You Get") editor. Macromedia Dreamweaver, Adobe GoLive, and Netscape Composer are examples of WYSIWYG tools. While you are creating the mockup, just save it to a file on your hard disk.

Anonymous User - Nov. 4, 2003 10:19 am:
Is this digression into using third party programs necessary at this point. It looks to me like we are trying
 to learn something about TAL.
 Is it conceivable that I simply create an index_html in the file library using Page Template and dump this
 code into it.
 Here are some good reasons to answer this question: 
 a) I did not succeed in saving my Netscape to the site; so I am not learning TAL;
 b) I created a Page Template and dumped the code into it, but got an error. Is that due to the fact than I
 did not use my editor to same the contents or is there another reason? I am not learning TAl.
 c) Importing from 3rd party software is not explained here; you have to go out to different documents then
 come back. You don't learn TAL.
 Tom Snell
Anonymous User - Nov. 4, 2003 10:21 am:
 did not use my editor to save the contents
Anonymous User - Nov. 13, 2003 4:24 pm:
 cant u just use notepad, c/p the contents, and save it as an html file?
joegold - Nov. 26, 2003 4:41 am:
 I found this confusing. I typed the sample into the Mozilla composer but didn't have the option of saving it
anywhere but my local file system. I tried typing in the http://localhost.../source.html but could not find a
combination that would work. I finally just created a Page Template named index_html and pasted in the code.
I
wasn't sure that would work because I'm a beginner and thought that maybe the described method does something
 different. It doesn't hurt to mention that they're available but it would also be nice to know that you can
 just past the code directly into Zope without going through the rest of it.
Orionrobots - Nov. 27, 2003 6:06 am:
 I think for now - you will probably need to use the ZMI to edit it- unless you have set up an external
 editor. The simplest way t6o use an external editor(until you read the section on setting one up) is to save
 it locally - and copy-paste the resulting code into the ZMI.
Anonymous User - June 13, 2004 6:09 pm:
 I start learning what i love in commercial software. If that's you intention with your Zope Book, you
 succeded.
 hands up, ppl
sbenes - Sep. 10, 2004 12:34 pm:
 Is there a way to achieve this without using external editors? If so, that would be the best path for
 learning here. Let's keep it simple and stick with the ZMI to learn TAL.

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:


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
                      "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <title>File Library</title>
  <style type="text/css">
  <!--
  .header {
    font-weight: bold;
    font-family: helvetica;
    background: #DDDDDD;
  }
  h1 {
    font-family: helvetica;
  }
  .filename {
    font-family: courier
  }
  -->
  </style>
  <meta name="GENERATOR" content="amaya 5.1">
</head>

<body>
<h1>File Library</h1>

<p>Click on a file below to download it.</p>

<table border="1" cellpadding="5" cellspacing="0">
  <tbody>
    <tr>
      <td class="header">Name</td>
      <td class="header">Type</td>
      <td class="header">Size</td>
      <td class="header">Last Modified</td>
    </tr>
    <tr>
      <td><a href="Sample.tgz" class="filename">Sample.tgz</a></td>
      <td>application/x-gzip-compressed</td>
      <td>22 K</td>
      <td>2001/09/17</td>
    </tr>
  </tbody>
</table>
</body>
</html>

Now, log into your Zope's management interface with your browser and create a folder called FileLib. In this folder, create a Page Template called index_html by selecting Page Template from the add menu, specifying the Id index_html in the form, and clicking Add. For information on creating a new Page Template via an external tool (as opposed to creating one in the ZMI and editing it afterwards with an external tool), see PUT_factory in the chapter entitled Using External Tools.

Now, with your HTML editor, using FTP, WebDAV (via the DAV "source port"), or HTTP PUT, save the above HTML to the URL of the index_html Page Template. For example, you may save to the URL http://localhost:8080/FileLib/index_html. Different editors have different mechanisms that you can use to do this. See the chapter entitled 'Using External Tools With Zope':ExternalTools.stx for more information on using WebDAV, FTP and HTTP PUT to communicate with Zope.

**NOTE: If you're trying to save to Zope via an editor like Netscape Composer or Amaya via HTTP PUT (as opposed to FTP or DAV), but you're having problems, try saving the file to http://localhost:8080/FileLib/index_html/source.html instead of the URL specified above. Appending /source.html to the Zope object name is a "hack" which Page Templates support to get around the fact that HTTP PUT attemtpts to render the page before doing the PUT, but we actually just want to save the unrendered source. If you're creating an XML file, the "magic" hackaround name is /source.xml instead of /source.html.**

Anonymous User - May 23, 2004 4:53 pm:
 This doesn't sound like a hackaround, but like a security risk to me.. Just like most ZOPE-WebDav's can be
 accessed without credentials (cadaver etc.) revealing the entire tree strutures & more.
 Any insights on this?

Now that you've saved the template, you can go back to Zope and click on index_html and then click on its Test tab to view the template. It looks just like it the mock-up, so everything is going well.

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 title 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:


<head>
  ...
  <title tal:content="template/title">File Library</title>
  ...

<body>
<h1 tal:content="template/title">File Library</h1>
...

Now go to Zope and change the title of the index_html page template to "My File Library". After saving that change, click the Test tab. As you can see, the Page Template dynamically inserted the "My File Library" title of the template object in the output of the template.

Anonymous User - Nov. 4, 2003 10:25 am:
 How does one view a Page Template?  This text always refers to the "Test" function.
We know that in dtml we can simply click on a folder and the default view is called. How does that work under
 TAL?
Orionrobots - Nov. 27, 2003 6:07 am:
 In the ZMI test is simply the view button with a different label.. Although I agree it is lacking a little
 consistency here..

Notice the new content tag attribute. This attribute says to "replace the content of this tag (the text between the h1 tags) with the variable 'template/title'". In this case, template/title is the title of the index_html Page Template.

The next bit of magic is to build a dynamic file list that shows you all the File objects in the FileLib folder.

To start, you need to write just one line of Python. Go to the FileLib folder and create a Script (Python) in that folder. Give the script the id files and click Add and Edit. Edit the script to contain the following Python code:


## Script (Python) "files"
## 
return container.objectValues(['File'])
Anonymous User - Nov. 4, 2003 10:52 am:
 Thanks. We are learning about TAL and three pages into it we are confronted with Python.
 Is there no way of doing this with TAL?
Anonymous User - Nov. 10, 2003 11:00 pm:
 No - there isn't (the short answer, but there are ways, it's just not the point). The point is to separate
 the presentation from the actual logic. If you want to do logic in your templates, take a look at DTML. If
you are reading this to build a web application, you *will* need to know Python. It's not easy learning brand
 new stuff, especially if you are in completely unfamiliar territory: take a break, plod through the reading
 (some things will be explained in time), and if you are still confused join the mailing list and ask some
 questions. I've found the best way is to play with it yourself. I admit that takes *a lot* of time, but you
 really won't know it otherwise.
Anonymous User - Nov. 20, 2003 9:35 am:
 The ['file'] bit means only return items in the folder which are files (as opposed to dtml methods or
 something) right?
 If you typed return container.objectValues() then you'd get everything in the folder, rather than just the
 files, right?
 Python: container.objectValues()
 TAL: content/objectValues

 These are referencing the same variable/property/thing just using different syntax. Yes?

 It would be nice to know what the ##'s are for.

 If this is really a newbie tutorial then it wouldn't do any harm to spoon feed us a bit ;-P
Anonymous User - Dec. 2, 2003 11:18 pm:
 To answer your questions:
 correct (but the capitalization is significant);
 correct; 
 yes;
 the lines that begin with # are comments which, in the case of zope's Python Scripts, are actually mildly
 significant in ways that will be explained in later chapters. IMHO those lines should be left out of this
 example, it's not necessary at this stage and it's just distracting.
Anonymous User - Jan. 17, 2004 8:30 am:
 could you explain the differences between

 container.objectValues(['File'])

 and

 container.objectValues('File')
ExileJedi - Jan. 18, 2004 3:25 pm:
 Looks like objectValues() takes a list of types of things to return, and returns you a list of items that
 match those types. The square brackets indicate a Python list, eg ['Fred','Barney','Wilma']. When you call
 container.objectValues(['File']), you just want the objects that are considered "File"s. You could call
 contain.objectValues(['File','Smurf']) if you also had objects that would be considered the "Smurf" type, as
opposed to the "File" type. If you instead call container.objectValues('File'), you can only get items of the
 one "File" type that you have passed; you're passing a string rather than a list.
Anonymous User - June 13, 2004 6:14 pm:
 Starting Zope, you need to know everything at once. And that is *pretty* much. If you start with TAL and ZPT
 (page templates), you need python to do this and somethin' else to do that. Even little "Hello World"-Apps
 tend to be like 4 to 5 objects in Zope with at least 500 statements with non of them easy to remember. And
 each part offers^H^H^H^H^H^H forces you with a new syntax.
Anonymous User - June 14, 2004 7:29 pm:
 I'll be the first to admit that the learning curve of zope is kinda steep at first. Just hang in there
 because it does get easier once it all makes sense. Zope is very powerful and you can do many things with
 just a few lines of python and a zpt. I can understand how difficult it could be for people with no
 experience with web applications.

This will return a list of any File objects in the FileLib folder. Now, edit your index_html Page Template and add some more tal attributes to your mock-up:


...
<tr tal:repeat="item container/files">
  <td><a href="Sample.tgz" class="filename"
         tal:attributes="href item/getId"
         tal:content="item/getId">Sample.tgz</a></td>
  <td tal:content="item/getContentType">application/x-gzip-compressed</td>
  <td tal:content="item/getSize">22 K</td>
  <td tal:content="item/bobobase_modification_time">2001/09/17</td>
</tr>
...
Anonymous User - Feb. 1, 2004 3:55 am:
As an extended exercise, you might want to create a script that returns all of the images in a folder and its
sub-folders. Then create a Zope template that displays the above information, the absolute and relative paths
 to the image, and the image itself (hopefully they aren't too large). As a further extension, limit the list
 to images of a certain size or type.

The interesting part is the tal:repeat attribute on the tr HTML tag. This attribute tells the template to iterate over the values returned by "container/files", which is the Python script you created in the current folder (the "container"), which returns a list of Zope objects. The repeat tag causes Zope to create a new table row with columns representing a bit of metadata about each of those objects. During each iteration, the current file object being iterated over is assigned the name item.

Anonymous User - Nov. 20, 2003 9:41 am:
With each pass through the loop the tal:repeat attribute creates a variable/property/thing named 'item' (this
 is an arbitrarily chosen name, it could be named anything) and pushes it into the namespace stack?
 This variable/property/thing references one of the file which was returned by the python script?

 On the first pass through the loop 'item' represents the first file returned by the python script?
 On the second pass through the loop 'item' represents the second file returned by the python script? etc...?
Anonymous User - Nov. 24, 2003 4:47 pm:
 the loop creates a "file" object and assigns it the name "item".
 You could call it george, tom , sally or foo. 
 On the first pass through the loop 'item' is an object which contains information about the first file ...
Anonymous User - Aug. 16, 2004 5:30 pm:
 Why can't this just be done in TAL itself ... why the roundaboutness of calling a script??

 <tr tal:repeat="item container/objectValues(['Image'])  doesn't work but 

 <tr tal:repeat="item container/file"> does work if the file script has:

 ##
 ## Script (Python): file
 ## 
 return container.objectValues(['Image'])

 This seems ripe for a simpler approach.
Anonymous User - Sep. 21, 2004 9:33 am:
 You don't have to use a script.
 You can use 

  <tr tal:repeat="item python:container.objectValues(['Image'])  this works without a script

The cells of each row all have tal:content attributes that describe 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 time replace the dummy data in the rows. Also notice how the anchor link dynamically points to the current file using tal:attributes to rewrite the href attribute.

This data comes from the item object by calling Zope API methods on what we know is a file object. The methods item/getId, item/getContentType, item/getSize, item/bobobase_modification_time are all standard API functions that are documented in Zope's online help system as well as in the various appendices to this book.

Anonymous User - May 5, 2004 9:09 am:
 This is probably one of the absolute *key* points for a beginner to understand, and it would benefit from
 more prominence. Understanding how TAL paths map to Zope API method names (ie, the mapping from item/id to
 item/getId to python:item.getId(), etc) is important, otherwise one can understand TAL, but be left in the
 dark as to what the available objects and paths are. --ben
Anonymous User - July 15, 2004 11:09 am:
 What's with "bobobase"? Does that refer to anything of significance in the Zope world?
Anonymous User - Nov. 14, 2004 4:05 am:
 I think "bobobase" refers to the underlying persistent store (database) in Zope. I remember seeing the name
 "bobobase" in a short history of Zope; I think it was the name of the database module of Zope's predecessor.

Go to Zope and test this script by first uploading some Files into the FileLib folder. This is done by selecting File from the add menu and clicking on the upload form button on the next screen. After uploading your file, you can just click Add. If you do not specify an id, then the filename of the file you are uploading will be used.

After uploading some files, go to the index_html Page Template and click the Test tab. Now, you can see the Page Template has rendered a very simple file library with just a few HTML tag attribute changes.

There are a few cosmetic problems with the file library as it stands. The size and date displays of the default content are very pretty, but the values returned from Zope don't match the format of the dummy content. Instead, they are "raw" numbers. 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:


## Script (Python) "file_size"
##
"""
Return a string describing the size of a file.
"""
bytes=context.getSize()
k=bytes/1024.0
mb=bytes/1048576.0
if mb > 1:
    return "%.2f MB" % mb
if k > 1:
    return "%d K" % k
return "%d bytes" % bytes
Anonymous User - Nov. 4, 2003 10:53 am:
 We are learning about TAL?
Anonymous User - Nov. 4, 2003 10:57 am:
 Might it be appropriate to state somewhere that Page Templates accomodate TAL, TALES, METAL and Python and
that TAL statements can use Python expressions if prefaced by python:? A header such as "Complex Expressions"
 might then be appropriate. Or is that "Advanced Page Templates"?
 I cannot penetrate TAL via this chapter.
Anonymous User - Nov. 20, 2003 9:51 am:
 So 'context' is a standard builtin Zope object, and 'getSize' is a standard builtin method of 'context' ??

 Using TAL syntax we activate the 'getsize' method of 'context' by making "context/getsize" the value of some
 TAL attribute (tal:something="context/getsize")??
 Using python syntax we activate the 'getsize' method of 'context' by typing:
 something=context.getSize()          or possibly:
 return context.getSize()

 Am I right or wrong?
Anonymous User - Dec. 2, 2003 11:22 pm:
 'context' is specific to Python Scripts. It means the same thing as 'here' in Page Templates. They really
 should have the same name in both; this is a historical wart. In a future version of zope (2.8?), 'context'
 will be available in Page Templates too and we can forget about 'here'.
 getSize is specific to objects that have size, such as Images and Files.

 otherwise, you are right.
vice - Aug. 11, 2004 11:02 pm:
 And don't forget the adquisition process that let's use the file_size (Python Script) method with every file
 in the container folder where the script was defined.
 I'm really enjoying learning Zope. You only need to get the 'logic'.

Create this script with the Id file_size in your FileLib 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 item/getSize expression:


...
<td tal:content="item/file_size">22 K</td>
...

Replacing this bit of TAL in your file_size template causes Zope to call the 'file_size" script on each object, returning the file's size. When the script runs during the loop, the "context" of the script is "item", which is a File object. This is an example of Zope's aquisition in action, as the file_size script is actually a sibling of the items in the folder, although it can be used as a method of the items in the folder. The expression item/file_size translates to "find a method of the object item named file_size. If the object named file_size has no "real" method named file_size, use acquisition to find a file_size method." Zope finds the Script (Python) file_size script and use it as a method of the item object.

Anonymous User - July 15, 2004 1:08 pm:
The second to last sentence should start: If the object named <code>item</code> has no "real"
method named
 <code>file_size</code>, ...
Is the "aquisition" magic explained anywhere? A link please. Does file_size have to be defined in the current
 folder or can it be defined in any parent folder as is the case with DTML?
Anonymous User - Jan. 30, 2005 9:52 am:
 "Replacing this bit of TAL in your file_size template" SHOULD BE "Replacing this bit of TAL in your
 index_html template"

You can also fix the date formatting problems with a little Python. Create a script named file_date in your FileLib folder:


## Script (Python) "file_date"
##
"""
Return modification date as string YYYY/MM/DD
"""
date=context.bobobase_modification_time()
return "%s/%s/%s" % (date.year(), date.month(), date.day())
Anonymous User - Nov. 20, 2003 9:59 am:
 The name of the Python script is file_date
 The script was called by passing the value item/file_date to the tal:content attribute
 (tal:content="item/file_date")
 Because of the way the script was called, the builtin object context now references item which references a
 file?
 bobobase_modification_time() is another standards built in method?

 date=context.bobobase_modification_time() calls this method on the file which is referenced by item which is
 referenced by context?
 The rest is just fancy formatting?

 Am I on the right track?
Anonymous User - Dec. 2, 2003 11:25 pm:
 You are on the right track.
Anonymous User - Jan. 8, 2004 8:46 pm:
 Regarding "bobobase_modification_time() is another standards built in method?" and "The rest is just fancy
 formatting?":
 To say the first thing, it might not be correctly formulated, but I think you have the right idea.
 bobobase_modification_time() is a method that can be called on any Zope object (since 'context' can take any
 Zope object as its value). Further, it returns a Python object which is apparently an abstraction of a date.
I don't know the name of the python class that this object instantiates, but objects of this class provide at
 least three methods (year(), month(), day()) which return string values. So yes, the fancy formatting part,
 the return statement, expects three string variables, which are provided by those three methods of the date
 object.

Now replace the item/bobobase_modification_time expression with a reference to this script:


...
<td tal:content="item/file_date">2001/9/17</td>
...

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).

Anonymous User - Dec. 2, 2003 8:05 pm:
 once i figgered out how to set the publish folder, & that the object needs to exist in the zope database
 before you publish to it, i found this part of the tutorial quite useful. i am interested in learning how to
use zope to build w/ markup and python, so i dont agree w/ the complaint that this shld be all about tal. the
 balance is pretty good
Anonymous User - Dec. 2, 2003 8:24 pm:
except that when i open index_html in mozilla composer, i get the expanded html, & if i change the file
&
 save it back, the expanded html overwrites the tal tags. i thought the tal was supposed to survive the round
 trip. wassup?
 jp
Anonymous User - Apr. 22, 2004 6:10 pm:
 IIRC, Mozilla Composer has a built-in "washer": The TAL attributes are naturally outside the specs that it
 tries to make the document conform to. Try looking for a way to turn the "washing" off.
Ideally, the template document should declare a DOCTYPE that includes the tal:xxx attributes as valid for all
 elements, cf. how the XHTML 1.0 or HTML 4.01 DTDs "include" the standard attributes like dir and id.
 As an aside, Microsoft Frontpage 2000 leaves it in. Of course FP has its own plethora of "extra" attributes
 it sometimes uses... :)
Anonymous User - May 8, 2004 6:24 pm:
 You have to edit the file that you get by the "Browse HTML source" link (=.../index_html/source.html), not
 the already parsed file. This lets you edit the file and leaves the tal tags intact.

Remote Editing with FTP and WebDAV

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 Macromedia Dreamweaver.

Anonymous User - Nov. 4, 2003 11:03 am:
 The fact that this section follows the introduction is proof of the pudding that the author was off base
 asking the reader above to use these methods to provide index_html with content.
 Tom Snell

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.

  1. Create a Page Template in the Zope Management interface. You can name it with whatever file extension you wish. Many folks prefer .html, while others prefer .zpt. Note, some names such as index_html have special meanings to Zope.
  2. Edit your file with your editor and then save it. When you save it you should use the same URL you used to retrieve it.
  3. Optionally reload your page after you edit it, to check for error comments. See the next section for more details on debugging.

You can create new Page Templates without using the Zope Management Interface. See the PUT_factory section of the chapter entitled Using External Tools for more information.

Debugging and Testing

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.

You may have already seen the 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 tal statements. For example:


<!-- Page Template Diagnostics
 Compilation failed
 TAL.TALDefs.TALError: bad TAL attribute: 'contents', at line 10, column 1
-->

This diagnostic message lets you know that you mistakenly used tal:contents rather than tal:content on line 10 of your template. Other diagnostic messages will tell you about problems with your template expressions and macros.

When you're using the Zope management interface to edit Page Templates it's easy to spot these diagnostic messages, because they are shown in the "Errors" header of the management interface page when you save the Page Template. 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.

If you don't notice the diagnostic message and try to render a template with problems you'll see a message like this:


Error Type: PTRuntimeError
Error Value: Page Template hello.html has errors.

That's your signal to reload the template and check out the diagnostic message.

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:


Error Type: Undefined
Error Value: "unicorn" not found in "here/unicorn"

This error message tells you that it cannot find the unicorn variable which is referenced in the expression, here/unicorn. To help you figure out what went wrong, Zope includes information about the environment in the traceback. This information will be available in your error_log (in your Zope root folder). The traceback will include information about the environment:


...
'here': <Application instance at 01736F78>,
'modules': <Products.PageTemplates.ZRPythonExpr._SecureModuleImporter instance at 016E77FC>,
'nothing': None,
'options': {'args': ()},
'request': ...
'root': <Application instance at 01736F78>,
'template': <ZopePageTemplate instance at 01732978>,
'traverse_subpath': [],
'user': amos})
...

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 here variable is an "Application instance". This means that it is the top-level Zope folder (notice how root variable is the same "Application instance"). Perhaps the problem is that you wanted to apply the template to a folder that had a unicorn property, but the folder to which you uploaded the template hasn't such a property.

XML Templates

Another example of the flexibility of Page Templates is that they can dynamically render XML as well as HTML. For example, in a chapter within this book entitled Creating Basic Zope Applications, you create the following XML:


<guestbook>
  <entry>
    <comments>My comments</comments>
  </entry>
  <entry>
    <comments>I like your web page</comments>
  </entry>
  <entry>
    <comments>Please no blink tags</comments>
  </entry>
</guestbook>
Anonymous User - July 20, 2004 7:48 am:
 When I'm reading a tutorial, I don't expect my mental parser to require lookahead. This example expects you
 to have read the next chapter already.

This XML is created by looping over all the DTML Documents in a folder and inserting their source into comment elements. In this section, we'll show you how to use Page Templates to generate this same XML.

Create a new Page Template called "entries.xml" in your guest book folder with the following contents:


<guestbook xmlns:tal="http://xml.zope.org/namespaces/tal">
  <entry tal:repeat="entry python:here.objectValues('DTML Document')">
    <comments tal:content="entry/document_src">Comment goes here...</comments>
  </entry>
</guestbook>
snell - Dec. 11, 2003 8:10 am:
 Is this section on Page Templates and TAL?
 Note: objectValues('DTML Document'). Replace that with objectValues('Page Templates') as by rights one
 should, and you get a very different result. And who knows how to clean it up?
ExileJedi - Jan. 18, 2004 4:45 pm:
 If you want to build the XML from a collection of DTML documents, then you'd still want to use
 here.objectValues('DTML Document') to match all the DTML documents in the directory. To build the XML from a
 collection of page templates, I believe you'd use objectValues('Page Template').
 All this example does is take all of the Zope objects of the specified type and jam their source into the
space between each <comments> and </comments>. If any of what you are jamming into the XML
document contains
 data that looks like an HTML tag, it will be properly quoted (turning the less-thans and greater-thans into
 their respective HTML character entities). This can make the resulting XML document look ugly if you just
 view it in your browser, but if you view the resulting document source, you'll see that it is "clean."
 Ideally, for a simple example like this, you'd want to use a bunch of files that aren't marked up with
 various tags, so as to minimize confusion.
 Also, you may be reading more significance into what's meant to be a really basic example of the fact that
 you can make XML documents just as easily as you can make HTML documents. It's just showing how to take some
 simple data and jam it into a structure of your design.

Make sure you set the content type to text/xml. Now, click Save Changes and click the Test 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.

Notice how the tal:repeat statement loops over all the DTML Documents. The tal:content statement inserts the source of each document into the comments element. The xmlns:tal attribute is an XML namespace declaration. It tells Zope that names that start with tal are Page Template commands. See Appendix C, "Zope Page Templates Reference" for more information about TAL and TALES XML namespaces.

Creating XML with Page Templates is almost exactly like creating HTML. The most important difference is that you must use "explicit" XML namespace declarations in the template text itself. Another difference is that you should set the content type to text/xml 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 source.xml rather than source.html.

Using Templates with Content

In general Zope supports content, presentation, and logic components. Page Templates are presentation components and they can be used to display content components.

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. 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 fairly basic and may not provide all of the features or metadata that you need.

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 technologies from and inspired by the CMF.

Anonymous User - Nov. 4, 2003 11:09 am:
 Having completed this chapter I now have a question:
 How does one display a Page Template?

 I have been told in paragraph one of this chapter that I can edit them from outside through the web.

 I have been told to use the "Test" button within Zope, but are there other possibilities?
Anonymous User - Nov. 19, 2003 1:51 am:
 My Zope server is running on http://localhost:8080
 I made a zope page template named 'display' in the folder 'sandbox' via the html management interface.
 When I pointed my browser to http://localhost:8080/sandbox/display the template displayed itself quite
 happily.
 I'm not sure if this would be exactly the same if you were running zope on a remote computer, but I presume
 so.
Anonymous User - Nov. 21, 2003 4:32 am:
 Summary of my Understanding from this chapter:
 (It could all be completely wrong)

 TAL basically works by substituting one thing for another.
 (The substitution takes place when the page is rendered by Zope)

 "TAL tags" are always of the form:

 tal:tag="value"

 "TAL tags" are embedded within standard HTML tags

 "TAL tags" which we have met in this chapter are:

 tal:content
 tal:replace
 tal:condition
 tal:repeat
 tal:attributes

 The easiest "TAL tags" to understand and tal:content and tal:replace

 tal:content substitutes its 'value' for whatever is enclosed by the
 HTML tag within which it is embedded.

 Example 'values' which the tal:content might take are:

 template/title    {The title of the template}
 request/URL       {The current URL}
 user/getUserName  {The current users name}

 (Its these "value" things which I understand the least)

 To test these out, create a template, give it a title and include
 in its body:

 <span tal:content="template/title"></span>
 <span tal:content="request/URL"></span>
 <span tal:content="user/getUserName"></span>

 I suspect that 'template', 'request' and 'user' are builtin Zope objects.
 I suspect that 'title' is a method of the 'template' object, 'URL' is a method of the 'request' object and
 'getUserName' is a method of the 'user' object.
 tal:replace is pretty simmilar to tal:content, except it replaces
 the whole tag, rather than just what is enclosed by the tag.

 To see the difference between tal:replace and tal:content, create
 a page templage and include the following in the body:

 <b><span tal:content="template/title"></span></b>
 <b><span tal:content="request/URL"></span></b>
 <b><span tal:content="user/getUserName"></span></b>
 <b><span tal:replace="template/title"></span></b>
 <b><span tal:replace="request/URL"></span></b>
 <b><span tal:replace="user/getUserName"></span></b>

Two of hese built in objects: 'template', 'request' and their methods can also be accessed by python scripts,
 but the third one 'user' doesn't seem to be accessable. I have no idea why. The syntax is also a little bit
 different when accessing these object/variable/property/vaue/things from python rather than TAL.
 For python we write:

 context.title               instead of    template/title
 context.REQUEST.URL()       instead of    request/URL

 To see how this works create two python script objects.
 Name them 'the_title' and 'the_url'

 Cut and paste the following into 'the_title'

 ## Script (Python) "files"
 ##
 return context.title

 Cut and paste the following into the_url

 ## Script (Python) "files"
 ##
 return context.REQUEST.URL

 Now change the ZPT so that it contains the following body:

 <span tal:content="template/the_title"></span>
 <span tal:content="template/the_url"></span>

 What is happening now is that the tal:content tag is taking as 
 its value the output of the scripts the_title and the_url

 Somehow 'template' gets mapped onto 'context' but I'm not sure how.

 Also I can't seem to find a way to acces 'user' via python.
 Its all quite confusing.

 I think that A LOT more discussion about the 'values' which tal attributes can take is needed.
 Also some discussion about which objects python scripts can access by default.
 And what the relationship is between the builtin object/value/property things which TAL can access,
 and the buildtin object/value/property things which python scripts can access.

 I hope these comments are useful to somebody who is going to rewrite this section, 
 rather than just annoying to other people who are trying to read it ;-P
Anonymous User - Dec. 2, 2003 9:18 pm:
 useful.  thanx.  you cld write the next chapter..

 ;7]
ExileJedi - Jan. 18, 2004 4:53 pm:
Anonymous from 11/21/03 - nice summary, and a fair assessment of what needs further elucidation. Rock on. :-)
Anonymous User - Apr. 2, 2004 8:51 am:
 nice job. Simple and clear. I wish this summary was at the beginning of the chapter.
Anonymous User - Apr. 2, 2004 3:42 pm:
 For "Best Results", the content vs replace section in the summary comment should change to
 -
  To see the difference between tal:replace and tal:content, create
  a page templage and include the following in the body:

  <b tal:content="template/title"></b>
  <b tal:content="request/URL"></b>
  <b tal:content="user/getUserName"></b>
  <b tal:replace="template/title"></b>
  <b tal:replace="request/URL"></b>
  <b tal:replace="user/getUserName"></b>
 -

 "tal:replace" affects the tag it is an attribute of.

 In the original line:
 <b><span tal:replace="user/getUserName"></span></b>

 the "tal:replace" will replace the <span> tag, leaving the bold tags.
 The rendered content will be exactly the same as the "tal:content" line.

 Also, I belive the exact zope equivalent of the python var "context.title" is "here/title"
 I believe "here" is the current object, I'm not entirely sure what "template" is.
Chirael - Apr. 3, 2004 12:13 am:
I hate to criticize documentation that is otherwise pretty good (relative to many other projects that is).
However,
 I really feel strongly that the documentation on the CMF is abysmally lacking here. If ZPT is the preferred
 method instead of DTML now and going forward, then there should be an actual section explaining the CMF; one
 paragraph just doesn't cut it.
 On a related note, the documentation on the CMF on the Zope web sites is also horrible. The "Using the CMF
 page", http://cmf.zope.org/Members/beehive/ZWACKChap5.html, goes into detail way too quickly without
 explaining basic concepts. I *wish* that page allowed per-paragraph commentary, because the long excerpts of
 poorly-formatted text could use some suggestions for improvement.
 I'm left with the undeniable impression that the CMF is both 1) very important to the present and future of
 Zope, and 2) very poorly documented. This is extremely frustrating.
Anonymous User - July 12, 2004 3:24 pm:
 Does anybody bother to read the comments and update glaring typos in the documentation? Zope is an absolute
 NON-STARTER for my organization, because what documentation does exist tends to be slipshod at best.
Anonymous User - July 13, 2004 11:39 am:
 i never read a more confusing an unstructured explanation of a technical theme than this 
 Zope-Doku!

Previous Page Up one Level Next Page Using Zope Page Templates Comments On/Off Table of Contents