You are not logged in Log in Join
You are here: Home » Zope Documentation » Books » The Zope Book Releases » The Zope Book (2.5 Edition) » Dynamic Content with DTML

Log in
Name

Password

 
Previous Page Up one Level Next Page Dynamic Content with DTML Comments On/Off Table of Contents

Chapter 4: Dynamic Content with DTML

DTML (Document Template Markup Language) is Zope's tag-based presentation and scripting language. DTML dynamically generates, controls, and formats content. DTML is commonly used to build modular and dynamic web interfaces for your web applications.

kaleissin - May 16, 2002 2:21 pm:
 DON'T OVERUSE IT! IT IS NOT A MAGIC BULLET! dtml-var, dtml-in, dtml-if and dtml-unless are ok. The
 loop-structs seem nice until you move away from the toys and try to make something that is to be used IRL.
Anonymous User - June 20, 2002 4:57 pm:
 irl?  in real life? (world?)
Anonymous User - July 16, 2002 6:45 pm:
 Is it true that Zope will phase out DTML in favor of Presentation Templates for presentation?

 Please do a search on the following page:

 http://dev.zope.org/Resources/ZopeDirections.html
Anonymous User - July 16, 2002 6:50 pm:
 "Phase out" is a poor choice of words on that page. Zope Corporation will itself use Page Templates for most
 of its presentation work, but DTML will continue to ship with Zope indefinitely, so you can use it all you
 like.

DTML is a server side scripting language, like SSI, PHP, ASP, and JSP. This means that DTML commands are executed by Zope at the server, and the result of that execution is sent to your web browser. By contrast, client-side scripting languages like Javascript are not processed by the server, but are rather sent to and executed by your web browser.

Anonymous User - June 13, 2002 9:57 pm:
 ASP is not actually a scripting language. It is a bunch of objects that may be manipulated by a variety of
 different scripting languages (much like Zope will work with Python and Perl). For example, in ASP a few
objects are the session object, the request object, and the response object. You call static methods on those
 objects using one of the supported scripting languages. For example, to store a session-state variable, you
would write: session("myVarName") = "Alpha" ... To write some output to the browser you would write:
response.write("hello
 world") ... to read values from the querystring, you might write something such as clientName =
 request.querystring("clientname")
Anonymous User - June 30, 2002 3:59 pm:
 Which, in combination with a scripting-language like VBScript, JavaAScript or 
 Python, is about the same thing as PHP, JSP, SSI (although slightly more 
 powerful :) and DTML: an in-line server-side HTML-preprocessing technique...
Anonymous User - Jan. 22, 2003 8:46 pm:
 Does DTML+Page Templates replace the need for JavaScript, WS

You can use DTML scripting in two types of Zope objects, DTML Documents and DTML Methods.

Anonymous User - Aug. 26, 2002 1:58 am:
 What are "DTML Documents" as compared to "DTML Methods" and when should one be used over the other?
Anonymous User - Oct. 7, 2002 2:57 pm:
 See previous Chapter...

Who is DTML For?

DTML is designed for people familiar with HTML and basic web scripting, not for application programmers. In fact, if you want to do programming with Zope you shouldn't use DTML. In Chapter 9, "Advanced Zope Scripting", we'll cover advanced programming using Python and Perl.

Anonymous User - June 6, 2002 9:03 am:
 link?
Anonymous User - July 8, 2002 11:31 am:
 This is now chapter 11.  The link is:

 http://www.zope.org/Documentation/ZopeBook/ScriptingZope.stx

DTML is for presentation and should be managed by web designers. Zope encourages you to keep your presentation and logic separate by providing different objects for presentation (DTML), and logic (Python, Perl, and others). You will find a host of benefits resulting from keeping your presentation in DTML and your logic in other types of Zope objects. Some of those benefits include:

  • Keeping logic and presentation separate makes it easy to vary either component without disrupting the other.
  • Often you will have different people in charge of maintaining logic and presentation. By using different objects for these tasks you make it easier for people to collaborate without disrupting each other.
  • It's easier to reuse existing presentation and logic components if they are not intermingled.

What is DTML Good for?

DTML is good for creating dynamic web interfaces. It supports reusing content and layout, formatting heterogeneous data, and separating presentation from logic and data.

For example with DTML you can reuse shared web page headers and footers:


<dtml-var standard_html_header>

<p>Hello world.</p>

<dtml-var standard_html_footer>
Anonymous User - May 3, 2002 4:21 am:
 lukas

This web page mixes HTML and DTML together. DTML commands are written as tags that begin with dtml-. This example builds a web page by inserting a standard header and footer into an HTML page. The resulting HTML page might look something like this:


<html>
<body bgcolor="#FFFFFF">

<p>Hello world.</p>

<hr>
<p>Last modified 2000/10/16 by AmosL</p>
</body>
</html>

As you can see the standard header defined a white background color and the standard footer added a note at the bottom of the page telling when the page was last modified and by whom.

In addition to reusing content, DTML lets you easily and powerfully format all kinds of data. You can use DTML to call methods, query databases, introspect Zope objects, process forms, and more.

For example when you query a database with a SQL Method it typically returns a list of results. Here's how you might use DTML to format each result from a database query:


<ul>
<dtml-in frogQuery>
  <li><dtml-var animal_name></li>
</dtml-in>
</ul>
Anonymous User - Oct. 8, 2002 4:51 pm:
But a ZSQL method doesn't normally return its list of results named by a variable, such as 'animal_name'. You
 should mark code that's for illustration purposes (ie, not working code) as such, the user who tries this,
 even if they create a SQL method called froqQuery that returns results, is going to see 'error, can't find
 animal_name'.

The DTML in tag iterates over the results of the database query and formats each result. Suppose four results are returned by frogQuery. Here's what the resulting HTML might look like:


<ul>
  <li>Fire-bellied toad</li>
  <li>African clawed frog</li>
  <li>Lake Nabu reed frog</li>
  <li>Chilean four-eyed frog</li>
</ul>

The results of the database query are formatted as an HTML bulleted list.

Note that you don't have to tell DTML that you are querying a database and you don't have to tell it where to find the arguments to call the database query. You just tell it what object to call, it will do the work of figuring out how to call the object and pass it appropriate arguments. If you replace the frogQuery SQL Method with some other kind of object, like a Script, a ZCatalog, or even another DTML Method, you won't have to change the way you format the results.

This ability to format all kinds of data makes DTML a powerful presentation tool, and lets you modify your business logic without changing your presentation.

When Not to Use DTML

DTML is not a general purpose programming language. For example, DTML does not allow you to create variables very easily. While it may be possible to implement complex algorithms in DTML, it is painful and not recommended. If you want to implement programming logic, use Python or Perl (for more information on these subjects, see Chapter 9, "Advanced Zope Scripting").

Anonymous User - June 6, 2002 9:04 am:
 link?
Anonymous User - July 8, 2002 11:44 am:
 This is now chapter 11.  The link is:

 http://www.zope.org/Documentation/ZopeBook/ScriptingZope.stx
Anonymous User - July 26, 2002 11:31 am:
 So... should Chapter numbers be automatically kept updated with DTML or scripting? I think each chapter
 should have a subject name with a chapter number assigned, such as ChapAdvZopeScriptNum should be "11" (and
 ChapAdvZomeScriptTitle is "Advanced Zope Scripting"). If the subject is changed enough that the name becomes
 wrong then all references have to be examined anyway.

For example, let's suppose you were writing a simple web page for a group of math students, and on that page you wanted to illustrate a simple calculation. You would not want to write the program that made this calculation in DTML. It could be done in DTML, but it would be difficult to understand. DTML would be perfect for describing the page that this calculation is inserted into, but it would be awful to do this calculation in DTML, whereas it may be very simple and trivial in Python or Perl.

Anonymous User - Aug. 6, 2002 2:40 pm:
 suggestion. Unbold/Unitalics "done" and bold/italics "could". --RAW--

String processing is another area where DTML is not the best choice. If you want to manipulate input from a user in a complex way, but using functions that manipulate strings, you are better off doing it in Python or Perl, both of which have much more powerful string processing abilities than DTML.

Anonymous User - Sep. 21, 2002 6:49 pm:
 /, but//

DTML is one tool among many available in Zope. If you find yourself scratching your head trying to figure out some complicated DTML construct, there's a good chance that things would work better if you broke your DTML script up into a collection of DTML and Python or Perl-based Scripts.

DTML Tag Syntax

DTML's syntax is similar to HTML. DTML is a tag based mark-up language. In other words DTML uses tags to do its work. Here is a simple snippet of DTML:


<dtml-var standard_html_header>

<h1>Hello World!</h1>

<dtml-var standard_html_footer>
Anonymous User - May 31, 2002 6:52 pm:
 <dtml-var standard_html_header>

 <h1>Hello World!</h1>

 <dtml-var standard_html_footer>

This DTML code contains two DTML var tags and some HTML. The h1 tags are HTML, not DTML. You typically mix DTML with other mark-up languages like HTML. Normally DTML is used to generate HTML, but there's nothing keeping you from generating other types of text. As you'll see later you can also use DTML to generate mail messages and other textual information.

DTML contains two kinds of tags, singleton and block tags. Singleton tags consist of one tag enclosed by less-than (<) and greater-than (>) symbols. The var tag is an example of a singleton tag:


<dtml-var parrot>
Anonymous User - Dec. 9, 2002 4:52 am:
 Can a person use a more XML friendly tag such as "<dtml-var parrot />"?

There's no need to close the var tag.

Anonymous User - Dec. 5, 2002 10:30 pm:
 ho

Block tags consist of two tags, one that opens the block and one that closes the block, and content that goes between them:


<dtml-in mySequence>

  <!-- this is an HTML comment inside the in tag block -->

</dtml-in>

The opening tag starts the block and the closing tag ends it. The closing tag has the same name as the opening tag with a slash preceding it. This is the same convention that HTML and XML use.

Anonymous User - Sep. 25, 2002 3:47 pm:
 Note however that empty tags such as <dtml-var foobar> would be written as either <dtml-var
 foobar></dtml-var> or <dtml-var foobar/> in XML.
 Note to newbies: an empty tags is a tag that has no *contents*. The "foobar" above is not a content of the
 "dtml-var" tag, but an attribute.

Using DTML Tag Attributes

All DTML tags have attributes. An attribute provides information about how the tag is supposed to work. Some attributes are optional. For example, the var tag inserts the value of a variable. It has an optional missing attribute that specifies a default value in case the variable can't be found:


<dtml-var wingspan missing="unknown wingspan">

If the wingspan variable is not found then unknown wingspan is inserted instead.

Some attributes don't have values. For example, you can convert an inserted variable to upper case with the upper attribute:


<dtml-var exclamation upper>
Anonymous User - June 6, 2002 9:15 am:
 is "exclamation" a variable like "wingspan" or an attribute like "missing" in the examples above?
mcdonc - June 6, 2002 9:18 am:
 the former (a variable)
Anonymous User - June 25, 2002 4:52 am:
 exclamation is a variable, upper is an attribute which doesn't have a value
Anonymous User - Sep. 21, 2002 7:02 pm:
 to be exact: its (the name of) a variable; the canonical dtml-tag here is
 <dtml-var name="exclamation" upper>
 Zope has plenty of defaults to ease life, but some of these are tripwires for newbies.

Notice that the upper attribute, unlike the missing attribute doesn't need a value.

Anonymous User - July 8, 2002 11:49 am:
 The link is:

 http://www.zope.org/Documentation/ZopeBook/CustomZopeObjects.stx

Different tags have different attributes. See Appendix A, "DTML Reference", for more information on the syntax of different DTML tags.

Anonymous User - June 6, 2002 9:17 am:
 link?
Anonymous User - Sep. 21, 2002 7:47 pm:
 Caveat: You can not nest dtml-tags inside dtml-tags like
 <dtml-var blah missing="<dtml-var default_blah>" >
Anonymous User - Oct. 9, 2002 10:08 am:
 And how can I do this ? Your example is just the problem, I just have.

Inserting Variables with DTML

Inserting a variable is the most basic task that you can perform with DTML. You already saw how DTML inserts a header and footer into a web page with the var tag. Many DTML tags insert variables, and they all do it in a similar way. Let's look more closely at how Zope inserts variables.

Suppose you have a folder whose id is Feedbags that has the title "Bob's Fancy Feedbags". Inside the folder create a DTML Method with an id of pricelist. Then change the contents of the DTML Method to the following:


<dtml-var standard_html_header>

<h1>Price list for <dtml-var title></h1>

<p>Hemp Bag $2.50</p>
<p>Silk Bag $5.00</p>

<dtml-var standard_html_footer>
Anonymous User - Apr. 27, 2002 6:39 pm:
 Why are we suddenly using a method? I would think the title insert would happen with either a document or a
 method and the rest of the document appears to be content, therefore use a document.
Anonymous User - Apr. 27, 2002 6:43 pm:
 Is the difference that a document has a title, even if null and a method never does so it always inherit's
 its container's title? If that is the case, why is a title prompted for in the ZMI?
Anonymous User - Aug. 29, 2002 11:15 am:
 Method works on its container (or, rather, its caller(AKA context)). All properties and content in method
 come from its context.
 Document does not care about context - it has its own properties. And it can't access content in a way that
 method can: method sees the content of folder it's called on, and a document is not a folder.

Now view the DTML Method by clicking the View tab. You should see an HTML page whose source looks something like this:


<html>
<body>

<h1>Price list for Bob's Fancy Feedbags</h1>

<p>Hemp Bag $2.50</p>
<p>Silk Bag $5.00</p>     

</body>
</html>
didopalauzov - July 3, 2002 6:40 am:
 Why is for written in red?
Anonymous User - July 3, 2002 8:51 am:
 Bad example parsing... it thinks the text is Python code. ;-)

This is basically what you might expect. Zope inserts a header, a footer, and a title into the web page. DTML gets the values for these variables from a number of different places. First, the var tag tries to find a variable in the current object. Then it looks in the current object's containers. Then it looks in the web request (forms and cookies). If Zope cannot find a variable then it raises an exception, and it stops executing the DTML.

Anonymous User - June 6, 2002 9:24 am:
 "current object's containers" what are containers? are you saying the current file's parent folder? or the
 sibling folders?
Anonymous User - June 6, 2002 9:31 am:
 the current object's folder, then in turn *its* folder, then its folder, etc.
Anonymous User - Aug. 20, 2002 11:05 am:
 The preceding search order is so important I think it should have its own heading.

 SL
Anonymous User - Sep. 12, 2002 5:15 pm:
 i agree
Anonymous User - Sep. 21, 2002 7:20 pm:
 Well, this is still shallow intro *examples* invoking a a lot of magic and wonders.
 Deeper discussions of namespace and the *rules* of name resolution see
 http://www.zope.org/Documentation/Books/ZopeBook/current/AppendixA.stx
 http://www.dieter.handshake.de/pyprojects/zope/book/chap3.html

Let's follow this DTML code step by step to see where the variables are found. First Zope looks for standard_html_header in the current object, which is the pricelist DTML Method. Next, Zope looks for the header in the current object's containers. The Feedbags folder doesn't have any methods or properties or sub-objects by that name either. Next Zope examines the Feedbags folder's container, and so on until it gets to the root folder. The root folder does have a sub-object named standard_html_header. The header object is a DTML Method. So Zope calls the header method and inserts the results.

Anonymous User - June 6, 2002 9:27 am:
 "Feedbags folder's container"... ok NOW I'm lost. A folder is NOT a container? or do you mean the parent
 folder of the Feedbag folder?
Anonymous User - June 6, 2002 9:33 am:
 a folder == a container. Note in the above description that "Feedbags" is a folder. It means the folder that
 contains the feedbag folder.
Anonymous User - June 6, 2002 3:35 pm:
 so...
 "container" = "parent"  ?
mcdonc - June 6, 2002 9:00 pm:
 Yes, in this particular case.
Anonymous User - June 10, 2002 9:40 am:
 so there are other meanings for "Container"?
 If so, please give reference where I might find more extensive definitions.
 Thanks!
mcdonc - June 10, 2002 9:47 am:
The word is not really a precise computer science term, it just means something that contains something else.
Anonymous User - Sep. 12, 2002 5:17 pm:
 in zope, i guess it is.
 from a python script you can call something like
 this().container()
 to afford a reference to the folder the script is
 located in. doesn't seem to work in dtml-expr's,
 though.
Anonymous User - Sep. 21, 2002 7:36 pm:
 <dtml-var standard_html_header> really is
 <dtml-var name="standard_html_header">, 
 and the object named "standard_html_header" is a DTML Method, hence callable
 (its (python!) class has a __call__-method). 
 DTML therefore *calls* standard_html_header and replaces the complete dtml-var tag with whatever this call
 returned.
 This automagically calling of callables makes DTML work miracles for experts and stuns laypersons!

Next Zope looks for the title variable. Here, the search is a little shorter. First, it looks in the pricelist DTML Method, which does not have a title, so Zope moves on and finds the Feedbags folder's title and inserts it.

Anonymous User - Aug. 29, 2002 11:21 am:
 Does not look like method's title is used in the search. Seems like it goes straight to context.
Anonymous User - Nov. 20, 2002 10:54 am:
 I agree.  I added a title for the pricelist method and did not make a difference.

Finally Zope looks for the standard_html_footer variable. It has to search all the way up to the root folder to find it, just like it looked for standard_html_header.

This exercise may seem a bit tedious, but understanding how Zope looks up variables is very important. For example, some important implications of how Zope looks up variables include how Zope objects can get content and behavior from their parents, and how content defined in one location can be reused by many objects.

Anonymous User - May 14, 2002 8:34 am:
 How do I access variables in a child folder?
 Is if only possible to access variables in a parent folder?
BubbaFett - May 23, 2002 9:34 am:
 Source: http://zope.nipltd.com/public/lists/zope-archive.nsf/ByKey/FD876D71D5F9F660

 You can use either:

     <dtml-with a_folder>
         <dtml-var a_doc>
     </dtml-with>

 or:

     <dtml-var "a_folder.a_doc()">

Processing Input from Forms

It's easy to do form processing with Zope. DTML looks for variables to insert in a number of locations, including information that comes from submitted HTML forms. You don't need any special objects, DTML Documents and DTML Methods will do.

Create two DTML Documents, one with the id infoForm and the other with the id infoAction. Now edit the contents of the documents. Here's the contents of the infoForm document:


<dtml-var standard_html_header>

<p>Please send me information on your aardvark adoption
program.</p>

<form action="infoAction">
name: <input type="text" name="user_name"><br>
email: <input type="text" name="email"><br>
<input type="submit">
</form>

<dtml-var standard_html_footer>

Now view this document. It is a web form that asks for information and sends it to the infoAction document when you submit the form.

Now edit the contents of the infoAction document to make it process the form:


<dtml-var standard_html_header>

<h1>Thanks <dtml-var user_name></h1>

<p>We received your request for information and will send you
email at <dtml-var email> describing our aardvark adoption
program as soon as it receives final governmental approval.
</p>

<dtml-var standard_html_footer>
Anonymous User - June 6, 2002 9:50 am:
<dtml-var email> (the one that 'should' restate the email address imput from infoForm) is not
displaying in
 infoAction. Why?
Anonymous User - June 6, 2002 9:56 am:
 I figured out why. (from a newbie no less!!!)

 the term "email" is causing the problem.

 Change in infoForm:
 email: <input type="text" name="email">
 to
 email: <input type="text" name="addy">

 and change in infoAction:
 <dtml-var email>
 to
 <dtml-var addy>

 and it now works properly.
Anonymous User - July 25, 2002 7:11 pm:
 Obviously the documentor is under sever time restriants unknown to us. Is it possible for someone who has
 more time but perhaps less experience to verify each example? I feel this is a useful suggestion as it would
 yield an increase in magnitude in time saved world-wide, since this one person's efforts could replace the
 efforts of that each individual user of this document would spend debugging the examples. The formerly
 mentioned case is especially inefficient because the majority of those proceeding through this document are
 not familiar with Zope.
Anonymous User - July 25, 2002 7:18 pm:
 This is actually the purpose of the comment system. If you notice a bug, enter a comment. When I edit the
 book, I review the comments, and fix what's broken. In the meantime, you can see the fixes in the comments
 rather than each person rediscovering the bug anew.
 The issue is more one of having time to edit the comments into the book prose. Please be aware that, yes, I
 am under severe time restraints. However, I am working steadily towards a revision of this book that
 incorporates all of the comments into the prose. It should be ready within a few weeks.
 - C
Anonymous User - Aug. 13, 2002 1:00 pm:
 Funny, but i am able to view the email address following the example above. <dtml-var email> works
krump - Aug. 27, 2002 12:03 am:
 The example worked on my installation. I did notice that after deliberatly misspelling 'email' zope aquired
 the default email on my sysytem. I almost missed the different email address in the result.
 If there is not already a discussion later on, on debugging aquisition errors I would not mind seeing one.

This document displays a thanks message which includes name and email information gathered from the web form.

Now go back to the infoForm document, view it, fill out the form and submit it. If all goes well you should see a thank you message that includes your name and email address.

Anonymous User - June 28, 2002 12:07 pm:
 Yes but I need to store his details in a DB or something if I'm gonna mail him. How does that work? -Ad.
Anonymous User - Sep. 25, 2002 3:55 pm:
 Keep on reading, or do the Zope Tutorial.

The infoAction document found the form information from the web request that happened when you clicked the submit button on the infoForm. As we mentioned in the last section, DTML looks for variables in a couple of places, one of which is the web request, so there's nothing special you need to do to enable your documents to process web forms.

Let's perform an experiment. What happens if you try to view the infoAction document directly, as opposed to getting to it from the infoForm document. Click on the infoAction document and then click the View tab, as shown in [4-1].

Anonymous User - Nov. 18, 2002 11:59 am:
 oi

DTML error resulting from a failed variable lookup.

Figure 4-1 DTML error resulting from a failed variable lookup.

Anonymous User - Nov. 18, 2002 12:00 pm:
 err

Zope couldn't find the user_name variable since it was not in the current object, its containers or the web request. This is an error that you're likely to see frequently as you learn Zope. Don't fear, it just means that you've tried to insert a variable that Zope can't find. In this example, you need to either insert a variable that Zope can find, or use the missing attribute on the var tag as described above:


<h1>Thanks <dtml-var user_name missing="Anonymous User"></h1>
Anonymous User - June 6, 2002 10:09 am:
 Is it possible to put the email address variable as the "missing=  " value?
 in other words, How do I put a variable inside a variable?

 <dtml-var user_name missing=<dtml-var addy>>  does not work
I get an error stating: "Invalid attribute name, "addy", for tag <dtml-var user_name missing=<dtml-var
addy>,
 on line 3 of infoAction"
 upon saving the changes (not even viewing it)

 <dtml-var user_name missing=addy> does not work
 I can save the form, but upon submitting, I get nothing from the "missing" variable, but the "...send you
 email at <dtml-var addy>..." IS working.
Anonymous User - June 6, 2002 10:26 am:
 <dtml-if user_name>
   <dtml-var user_name>
 <dtml-else>
   <dtml-var addy>
 </dtml-if>
Anonymous User - June 10, 2002 10:00 am:
 Hey! That works! Thanks!

 the new code for the enitre infoAction page (the vesrion that puts the Email Addy in place of the Name if no
 Name supplied) would be:
 <dtml-var standard_html_header> 

 <h1>Thanks <dtml-if user_name>
    <dtml-var user_name>
  <dtml-else>
    <dtml-var addy>
  </dtml-if> </h1> 

<p>We received your request for information and will send you email at <dtml-var addy> describing
our
 aardvark adoption program as soon as it receives final governmental approval. </p>
 <dtml-var standard_html_footer>
Anonymous User - June 13, 2002 11:01 pm:
 Glad that the examples in the above comments work, but I think they're pretty tangential to the flow of
 instruction here and might confuse someone new to web programming.
Anonymous User - July 26, 2002 7:23 am:
 By the last dtml-var addy, shouldn't be there such an IF clause too???

Understanding where Zope looks for variables will help you figure out how to fix this kind of problem. In this case, you have viewed a document that needs to be called from an HTML form like infoForm in order to provide variables to be inserted in the output.

Dynamically Acquiring Content

Zope looks for DTML variables in the current object's containers if it can't find the variable first in the current object. This behavior allows your objects to find and use content and behavior defined in their parents. Zope uses the term acquisition to refer to this dynamic use of content and behavior.

Anonymous User - June 6, 2002 10:16 am:
 Here we go with "Containers"  Please define "Containers"
Anonymous User - June 6, 2002 10:24 am:
A container is any object that contains any other object. "Folder" objects are containers. "ZCatalog" objects
 are containers. "Temporary Folder" objects are containers. Basically anything that exposes a view that shows
 you a collection of subobjects is a container.
Anonymous User - June 10, 2002 10:04 am:
 Thank you! That helps GREATLY!
Anonymous User - June 13, 2002 11:04 pm:
 Let me add a bit more: In the absctract (the way the word "containers" is used in code-speak), lists, bags,
 boxes, folders, etc. etc. are containers. Anything that can hold things is a container. The term is usually
 used to describe something that can hold any kind of object (you could have a box full of boxes, a list full
 of lists, or a list full of boxes, for example.

Now that you see how site structure fits into the way names are looked up, you can begin to understand that where you place objects you are looking for is very important.

Anonymous User - July 25, 2002 7:25 pm:
I'm not sure if this would be the place to introduce this, and perhaps it is explained later in this document
 (I have not finished it yet), but if I have an object in 'root' like 'standard_header' which references
another object like 'default_style_sheet', if I redefine 'default_style_sheet' in some folder somewhere lower
 in the heirarchy and have some other object in that folder which references 'standard_header', which
 'default_style_sheet' is used? This may or may not be an advanced OOP issue but it was the first question
 which came to mind when I saw the sentence "Now that you see how site structure fits into the way names are
 looked up, you can begin to understand that where you place objects you are looking for is very important. "

An example of acquisition that you've already seen is how web pages use standard headers and footers. To acquire the standard header just ask Zope to insert it with the var tag:


<dtml-var standard_html_header>

It doesn't matter where your DTML Method or Document is located. Zope will search upwards until it finds the standard_html_header that is defined in the root folder.

Anonymous User - Sep. 21, 2002 7:55 pm:
 More explicit: it takes the *first* one encountered in the lookup. Important!

You can take advantage of how Zope looks up variables to customize your header in different parts of your site. Just create a new standard_html_header in a folder and it will override global header for all web pages in your folder and below it.

Create a folder in the root folder with an id of Green. Enter the Green folder and create a DTML Document with an id of welcome. Edit the welcome document to have these contents:


<dtml-var standard_html_header>

<p>Welcome</p>

<dtml-var standard_html_footer>

Now view the welcome document. It should look like a simple web page with the word welcome, as shown in [4-2].

Welcome document.

Figure 4-2 Welcome document.

Now let's customize the header for the Green folder. Create a DTML Method in the Green folder with an id of standard_html_header. Then edit the contents of the header to the following:


<html>
<head>
  <style type="text/css">
  body {color: #00FF00;}
  p {font-family: sans-serif;}
  </style>
</head>
<body>
Anonymous User - July 1, 2002 4:46 am:
 !!!!!!!!!!!!

 That's a bug of some sort, surely. Don't put that last line, "ERROR:..." into your code, people!
krump - Aug. 27, 2002 12:10 am:
 It workds ok.  Remember it is just a header file and will be prepended to the 'welcome' object.
Anonymous User - Sep. 3, 2002 1:32 pm:
 This is the correct code:

 <html>
 <head>
   <style type="text/css">
   body {color: #00FF00;}
   p {font-family: sans-serif;}
   </style>
 </head>
 <body>
 </body>
 </html>
Anonymous User - Sep. 11, 2002 6:51 pm:
 No, the comment from Sep. 3, 2002 1:32 pm is WRONG. The </body> and </html> will come from
 standard_html_footer, so DON'T put them into the header, please.
Anonymous User - Sep. 21, 2002 10:20 am:
 It is a part of HTML code.

 A|F| <html>
 A|F| <head>
 A|F|   <style type="text/css">
 A|F|   body {color: #00FF00;}
 A|F|   p {font-family: sans-serif;}
 A|F|   </style>
 A|F| </head>
 A|F| <body>
 B|F| blub,blub,blub.....
 B|F| blub,blub,blub.....
 C|F| </body>
 C|F| </html>

 F| is HTML full code.
 A| is code of part A.
 B| is code of part B.
 C| is code of part C.
Anonymous User - Sep. 21, 2002 10:26 am:
 And, part A| copy to a DTML Method id of standard_html_header.

Notice that this is not a complete web page. This is just a fragment of HTML that will be used as a header. This header uses CSS (Cascading Style Sheets) to make some changes to the look and feel of web pages.

Now go back to the welcome document and view it again, as shown in [4-3].

Welcome document with custom header.

Figure 4-3 Welcome document with custom header.

Anonymous User - Sep. 21, 2002 8:01 pm:
 This light green on light grey is hardly visible.

The document now looks quite different. This is because it is now using the new header we introduced in the Green folder. This header will be used by all web pages in the Green folder and its sub-folders.

Anonymous User - Nov. 21, 2002 4:27 pm:
 to get the diffrence between comments and stupidity

 see above...

You can continue this process of overriding default content by creating another folder inside the Green folder and creating a standard_html_header DTML Method there. Now web pages in the sub-folder will use their local header rather than the Green folder's header. Using this pattern you can quickly change the look and feel of different parts of your web site. If you later decide that an area of the site needs a different header, just create one. You don't have to change the DTML in any of the web pages; they'll automatically find the closest header and use it.

Using Python Expressions from DTML

So far we've looked at simple DTML tags. Here's an example:


<dtml-var getHippo>

This will insert the value of the variable named getHippo, whatever that may be. DTML will automatically take care of the details, like finding the variable and calling it. We call this basic tag syntax name syntax to differentiate it from expression syntax.

Anonymous User - Sep. 21, 2002 8:24 pm:
 A *variable* is a pair (name, value) where in most cases value is an object of some class. 
 (python has yet not completely unified _simple types_ (eg 'int') and classes).
 *If* value is callable, its called and the result of the call inserted. 
 If value is not callable (like for integers), the value itself is inserted.
 As DTML is about textual replacement in both cases a suitable string representation is inserted. (for
 integers the usual one).

DTML expressions allow you to be more explicit about how to find and call variables. Expressions are tag attributes that contain snippets of code in the Python language. For example, instead of letting DTML find and call getHippo, we can use an expression to explicitly pass arguments:


<dtml-var expr="getHippo('with a large net')">
kaleissin - May 16, 2002 2:27 pm:
 Don't. Here Be Dragons. (Not to mention escape-hell :) )
Anonymous User - Sep. 21, 2002 8:27 pm:
 Hm. a "DTML expression" is an expr inside a dtml-tag, not one made out of dtml-tags.
Anonymous User - Sep. 24, 2002 5:37 pm:
 /DTML expressions/Expr attributes/

Here we've used a Python expression to explicitly call the getHippo method with the string argument, with a large net. To find out more about Python's syntax, see the Python Tutorial at the Python.org web site. Many DTML tags can use expression attributes.

Expressions make DTML pretty powerful. For example, using Python expressions, you can easily test conditions:


<dtml-if expr="foo < bar">
  Foo is less than bar.
</dtml-if>

Without expressions, this very simple task would have to be broken out into a separate method and would add a lot of overhead for something this trivial.

Before you get carried away with expressions, take care. Expressions can make your DTML hard to understand. Code that is hard to understand is more likely to contain errors and is harder to maintain. Expressions can also lead to mixing logic in your presentation. If you find yourself staring blankly at an expression for more than five seconds, stop. Rewrite the DTML without the expression and use a Script to do your logic. Just because you can do complex things with DTML doesn't mean you should.

DTML Expression Gotchas

Using Python expressions can be tricky. One common mistake is to confuse expressions with basic tag syntax. For example:


<dtml-var objectValues>
Anonymous User - June 6, 2002 11:24 am:
 link?
Anonymous User - June 6, 2002 11:25 am:
 wrong place should be under Chapter 8 reference.

and:


<dtml-var expr="objectValues">

will end up giving you two completely different results. The first example of the DTML var tag will automatically render variables. In other words it will try to do the right thing to insert your variable, no matter what that variable may be. In general this means that if the variable is a method it will be called with appropriate arguments. This process is covered more thoroughly in Chapter 8, "Variables and Advanced DTML".

In an expression, you have complete control over the variable rendering. In the case of our example, objectValues is a method. So:


<dtml-var objectValues>

will call the method. But:


<dtml-var expr="objectValues">

will not call the method, it will just try to insert it. The result will be not a list of objects but a string such as <Python Method object at 8681298>. If you ever see results like this, there is a good chance that you're returning a method, rather than calling it.

Anonymous User - Sep. 21, 2002 8:36 pm:
 The result will be not a list of objects 
 but a string such as '<Python Method object at 8681298>'
Anonymous User - Sep. 21, 2002 9:17 pm:
<dtml-var "objectValues"> will insert a suitable ersatz representation like the string "<Python
Method object
at 8681298>". This usually will not be visible in a browser since a browser treats anything between "<"
and
 ">" that it does not recognize as HTML as unknown tag, but it will be visible, when you view the source.
If you really want to see the ersatz repr, <dtml-var "objectValues" html_quote> delivers
"&lt;Python Method
 object at 8681298&gt;" which a browser shows.

To call a method from an expression, you must use standard Python calling syntax by using parenthesis:


<dtml-var expr="objectValues()">

The lesson is that if you use Python expressions you must know what kind of variable you are inserting and must use the proper Python syntax to appropriately render the variable.

Before we leave the subject of variable expressions we should mention that there is a deprecated form of the expression syntax. You can leave out the "expr=" part on a variable expression tag. But please don't do this. It is far too easy to confuse:


<dtml-var aName>

with:


<dtml-var "aName">
Anonymous User - Dec. 8, 2002 2:56 am:
 nice tutorial

and get two completely different results. These "shortcuts" were built into DTML long ago, but we do not encourage you to use them now unless you are prepared to accept the confusion and debugging problems that come from this subtle difference in syntax.

Anonymous User - Sep. 21, 2002 8:40 pm:
 The mailing list documents lot of pain cries.
 If its in double quotes, its in python.

The Var Tag

The var tag inserts variables into DTML Methods and Documents. We've already seen many examples of how the var tag can be used to insert strings into web pages.

As you've seen, the var tag looks up variables first in the current object, then in its containers and finally in the web request.

The var tag can also use Python expressions to provide more control in locating and calling variables.

Var Tag Attributes

You can control the behavior of the

var

tag using its attributes. The

var

tag has many attributes that help you in common formatting situations. The attributes are summarized in Appendix A. Here's a sampling of

var

tag attributes.

html_quote
This attribute causes the inserted values to be HTML quoted. This means that '<', '> and &' are escaped.

missing
The missing attribute allows you to specify a default value to use in case Zope can't find the variable. For example:

<dtml-var bananas missing="We have no bananas">

fmt
The fmt attribute allows you to control the format of the var tags output. There are many possible formats which are detailed in Appendix A.

One use of the fmt attribute is to format monetary values. For example, create a float property in your root folder called adult_rate. This property will represent the cost for one adult to visit the Zoo. Give this property the value 2.2.

Anonymous User - June 6, 2002 11:54 am:
 link to Appendix A?
Anonymous User - July 1, 2002 4:52 am:
 How in the world do I "create a float property" in my root folder?
Anonymous User - July 2, 2002 2:29 am:
Not quite sure what "create a float property" exactly means either, but making a new Python script which just
 contains "return (2.2)" seems to do the trick. Is this the correct interpretation?
Anonymous User - July 3, 2002 10:13 am:
 Go to the Properties tab in the root folder. Here you will find the correct fields.
Anonymous User - Jan. 23, 2003 4:17 pm:
 Since this is supposed to illustrate fmt, not float properties, how about:
 <dtml-var "5.4876" fmt=dollars-and-cents>

You can display this cost in a DTML Document or Method like so:


One Adult pass: <dtml-var adult_rate fmt=dollars-and-cents>
Anonymous User - Aug. 16, 2002 10:55 am:
 Do I find other fmt-formats in the Appendix A as well?

This will correctly print "$2.20". It will round more precise decimal numbers to the nearest penny.

Var Tag Entity Syntax

Zope provides a shortcut DTML syntax just for the simple var tag. Because the var tag is a singleton, it can be represented with an HTML entity like syntax:


&dtml-cockatiel;
Anonymous User - June 13, 2002 11:13 pm:
 &dtml-cockatiel;
 <p>
 What is it about this expression that creates the equivalancy with the html-quote attribute of the dtml tag
format? I am confused b/c I do not see anything different about the HTML entity sequence between this example
 and the next one.
SmileyChris - July 16, 2002 7:38 pm:
 I would like to see a bigger section explaining DTML entity syntax
 http://www.zope.org/Members/AlexR/EntitySyntax has a great article explaining new features such as
 &dtml.lower-YourVariable; etc.

This is equivalent to:


<dtml-var name="cockatiel" html_quote>

The main reason to use the entity syntax is to avoid putting DTML tags inside HTML tags. For example, instead of writing:


<input type="text" value="<dtml-var name="defaultValue">">

You can use the entity syntax to make things more readable for you and your text editor:


<input type="text" value="&dtml-defaultValue;">

The var tag entity syntax is very limited. You can't use Python expressions and some tag attributes with it. See Appendix A for more information on var tag entity syntax.

Anonymous User - June 3, 2002 3:55 pm:
 "You can't use Python expressions and some tag                                  attributes with it."
The above statement is a bit confusing and poorly constructed. Perhaps it should read, "You cannot mix Python
 expressions and tag attributes". But then I'm not sure that's what it means. I'd also like to see an example
 or two of "illegal" structures.
Anonymous User - June 13, 2002 6:26 pm:
 As I understand it, you cannot use attributes with the var tag entity syntax.
 It always uses the html_quote attribute, which you cannot remove.
 Nor is there a syntax to add other attributes that I'd know of.

 So the sentence should probably read:
 "You cannot use Python expressions or tag attributes with it."

The If Tag

One of DTML's important benefits is to let you customize your web pages. Often customization means testing conditions and responding appropriately. This if tag lets you evaluate a condition and carry out different actions based on the result.

What is a condition? A condition is either a true or false value. In general all objects are considered true unless they are 0, None, an empty sequence or an empty string.

Here's an example condition:

objectValues
True if the variable objectValues exists and is true. That is to say, when found and rendered objectValues is not 0, None, an empty sequence, or an empty string.

As with the

var

tag, you can use both name syntax and expression syntax. Here are some conditions expressed as DTML expressions.

expr="1"
Always true.

expr="rhino"
True if the rhino variable is true.

expr="x < 5"
True if x is less than 5.

expr="objectValues(File)"
True if calling the objectValues method with an argument of File returns a true value. This method is explained in more detail in this chapter.

Anonymous User - Sep. 21, 2002 8:51 pm:
 Nonexistence in the if-tag: name syntax: falsehood, expr syntax: not found exception.

The if tag is a block tag. The block inside the if tag is executed if the condition is true.

Anonymous User - June 5, 2002 11:12 am:
 " expr="objectValues('File')"
 True if calling the objectValues method with an argument of File returns a true value."

 Should read "True if calling the objectValues Python method..."
Anonymous User - Sep. 21, 2002 8:57 pm:
 /argument of File/argument of 'File'/ and unitalic/unbold _*File*_, heres a string!

Here's how you might use a variable expression with the if tag to test a condition:


<p>How many monkeys are there?</p>

<dtml-if expr="monkeys > monkey_limit">
  <p>There are too many monkeys!</p>
</dtml-if>

In the above example, if the Python expression monkeys > monkey_limit is true then you will see the first and the second paragraphs of HTML. If the condition is false, you will only see the first.

If tags be nested to any depth, for example, you could have:


<p>Are there too many blue monkeys?</p>

<dtml-if "monkeys.color == 'blue'">
  <dtml-if expr="monkeys > monkey_limit">
    <p>There are too many blue monkeys!</p>
  </dtml-if>
</dtml-if>
Anonymous User - July 10, 2002 4:05 am:
 If tags be nested -> If tags *can* be nested
Anonymous User - July 18, 2002 12:57 pm:
is the tag <dtml-if "monkeys.color == 'blue'"> really valid, or the attribute expr need to be added
inside?
Anonymous User - Sep. 21, 2002 9:00 pm:
 If its in quotes, its in python like in 'expr="..."'

Nested if tags work by evaluating the first condition, and if that condition is true, then evaluating the second. In general, DTML if tags work very much like Python if statements..

Name and Expression Syntax Differences

The name syntax checks for the existence of a name, as well as its value. For example:


<dtml-if monkey_house>
  <p>There <em>is</em> a monkey house Mom!</p>
</dtml-if>  
Anonymous User - June 3, 2002 3:59 pm:
I know this is picky but if you are telling Mom there is a monkey house, you need a comma after house. If you
 are suggesting the existence of "monkey_house" equates to the fact there is a "monkey house Mom" then you're
 OK. Hey you guys put the bloody comment buttons in here. 8)

If the monkey_house variable does not exist, then this condition is false. If there is a monkey_house variable but it is false, then this condition is also false. The condition is only true is there is a monkey_house variable and it is not 0, None, an empty sequence or an empty string.

The Python expression syntax does not check for variable existence. This is because the expression must be valid Python. For example:


<dtml-if expr="monkey_house">
  <p>There <em>is</em> a monkey house, Mom!</p>
</dtml-if>

This will work as expected as long as monkey_house exists. If the monkey_house variable does not exist, Zope will raise a KeyError exception when it tries to find the variable.

Else and Elif Tags

The if tag only lets you take an action if a condition is true. You may also want to take a different action if the condition is false. This can be done with the DTML else tag. The if block can also contain an else singleton tag. For example:


<dtml-if expr="monkeys > monkey_limit">
  <p>There are too many monkeys!</p>
<dtml-else>
  <p>The monkeys are happy!</p>
</dtml-if>

The else tag splits the if tag block into two blocks, the first is executed if the condition is true, the second is executed if the condition is not true.

A if tag block can also contain a elif singleton tag. The elif tag specifies another condition just like an addition if tag. This lets you specify multiple conditions in one block:


<dtml-if expr="monkeys > monkey_limit">
  <p>There are too many monkeys!</p>
<dtml-elif expr="monkeys < minimum_monkeys">
  <p>There aren't enough monkeys!</p>
<dtml-else>
  <p>There are just enough monkeys.</p>
</dtml-if>
Anonymous User - Sep. 30, 2002 5:14 pm:
 could you add a paragraph about multiple conditions?
 I cant seem to guess the syntax for "monkeys=='true' or color=='blue'">
 python conditional operators arent working.

An if tag block can contain any number of elif tags but only one else tag. The else tag must always come after the elif tags. Elif tags can test for condition using either the name or expression syntax.

Anonymous User - Sep. 21, 2002 9:24 pm:
 /test for condition/test for a condition/

Using Cookies with the If Tag

Let's look at a more meaty if tag example. Often when you have visitors to your site you want to give them a cookie to identify them with some kind of special value. Cookies are used frequently all over the Internet, and when they are used properly they are quite useful.

Anonymous User - Nov. 13, 2002 6:08 pm:
 mmmm I wish I had a cookie
Anonymous User - Jan. 23, 2003 11:15 pm:
 You've got an anonymous user cookie

Suppose we want to differentiate new visitors from folks who have already been to our site. When a user visits the site we can set a cookie. Then we can test for the cookie when displaying pages. If the user has already been to the site they will have the cookie. If they don't have the cookie yet, it means that they're new.

Suppose we're running a special. First time zoo visitors get in for half price. Here's a DTML fragment that tests for a cookie using the hasVisitedZoo variable and displays the price according to whether a user is new or a repeat visitor:


<dtml-if hasVisitedZoo>
  <p>Zoo admission <dtml-var adult_rate fmt="dollars-and-cents">.</p>
<dtml-else>
  <b>Zoo admission for first time visitors
       <dtml-var expr="adult_rate/2" fmt="dollars-and-cents"></p>
</dtml-if>  
Anonymous User - Aug. 31, 2002 4:21 pm:
 Hmm. This piece of DTML contains no code to set the cookie if it's the user's first time visit, wheras the
 "equivalent" python does. How would you set a cookie in DTML ?
                                -Liam
Anonymous User - Sep. 12, 2002 5:20 pm:
 why not
 <dtml-call "RESPONSE.setCookie('zooVisitCookie', '1')">
 ?
Anonymous User - Sep. 21, 2002 9:30 pm:
 /special./special offer:/
 I know its picky, my english not perfect, stumbled here.

This fragment tests for the hasVisitedZoo variable. If the user has visited the zoo before it displays the normal price for admission. If the visitor is here for the first time they get in for half-price.

Just for completeness sake, here's an implementation of the hasVisitedZoo method as a Python-based Script:


## Script(Python) "hasVisitedZoo"
##parameters=REQUEST, RESPONSE
##
"""
Returns true if the user has previously visited
the Zoo. Uses cookies to keep track of zoo visits.
"""
if REQUEST.has_key('zooVisitCookie'):
    return 1
else:
    RESPONSE.setCookie('zooVisitCookie', '1')
    return 0
Anonymous User - Apr. 20, 2002 2:50 pm:
 I think this needs to be updated.  I did get this to work though:

 ## Script (Python) "hasVisitedZoo"
 ##bind container=container
 ##bind context=context
 ##bind namespace=
 ##bind script=script
 ##bind subpath=traverse_subpath
 ##parameters=
 ##title=hasVisitedZoo
 ##
 """
 Returns true if the user has previously visited
 the zoo.  Uses cookies to keep track of zoo visits.
 """
 from Products.PythonScripts.standard import html_quote
 request = container.REQUEST
 RESPONSE =  request.RESPONSE

 if request.has_key('zooVisitCookie'):
   return 1
 else:
   RESPONSE.setCookie('zooVisitCookie', '1')
   return 0
krump - Aug. 27, 2002 12:12 am:
 Cutting and pasting seems to work so long as it is pasted into a Python script.
Anonymous User - Nov. 20, 2002 2:58 pm:
 The reason why cutting and pasting the above code does not work is because there are two spaces in front of
 each line. Deleting the spaces will fix the problem.

In Chapter 10, "Advanced Zope Scripting" we'll look more closely at how to script business logic with Python and Perl. For now it is sufficient to see that the method looks for a cookie and returns a true or false value depending on whether the cookie is found or not. Notice how Python uses if and else statements just like DTML uses if and else tags. DTML's if and else tags are based on Python's. In fact Python also has an elif statement, just like DTML.

The In Tag

The DTML in tag iterates over a sequence of objects, carrying out one block of execution for each item in the sequence. In programming, this is often called iteration, or looping.

The in tag is a block tag like the if tag. The content of the in tag block is executed once for every iteration in the in tag loop. For example:


<dtml-in todo_list>
  <p><dtml-var description></p>
</dtml-in>

This example loops over a list of objects named todo_list. For each item, it inserts an HTML paragraph with a description of the to do item.

Iteration is very useful in many web tasks. Consider a site that display houses for sale. Users will search your site for houses that match certain criteria. You will want to format all of those results in a consistent way on the page, therefore, you will need to iterate over each result one at a time and render a similar block of HTML for each result.

In a way, the contents of an in tag block is a kind of template that is applied once for each item in a sequence.

Iterating over Folder Contents

Here's an example of how to iterate over the contents of a folder. This DTML will loop over all the files in a folder and display a link to each one. This example shows you how to display all the "File" objects in a folder, so in order to run this example you will need to upload some files into Zope as explained in the previous chapter:


<dtml-var standard_html_header>
<ul>
<dtml-in expr="objectValues('File')">
  <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></li>
</dtml-in>
</ul>
<dtml-var standard_html_footer>
Anonymous User - May 30, 2002 10:52 pm:
 this code doesn't work, i've uploaded some files to the folder, and copied and pasted this code to a DTML
 document, but nothing come out!
Anonymous User - May 30, 2002 11:32 pm:
 Are you sure they were honest-to-god File objects and not DTML Methods or DTML Documents or something?
Anonymous User - May 31, 2002 12:00 am:
 of course!
 but it works after i've specified the folder name, the correct coding should be 
 <dtml-in expr="foldername.objectValues('File')">
Anonymous User - May 31, 2002 12:38 am:
 I've got another finding, the post-out coding is working under DTML method, but if using DTML document, have
 to do what i said, specified the folder name. :)
Anonymous User - June 12, 2002 6:49 am:
 Please be aware that 'honest-to-god' File objects seem to be a bit of an elitist group... when trying to
iterate over folders containing pictures, I actually had to use <dtml-in expr="objectValues('Image')">.
mcdonc - June 15, 2002 11:44 am:
 Right. That's because File objects have a "meta_type" of File while Image objects have a meta_type of
 "Image". Try objectValues(('File', 'Image')) to get both.
Anonymous User - Oct. 16, 2002 7:53 am:
How about if you are trying to iterate over DTML documents - i.e.: produce a navigation list? I've tried both
 <dtml-in expr="oral_microbiology.objectValues('Document')"> and
 <dtml-in expr="oral_microbiology.objectValues('Documents')">
Anonymous User - Nov. 23, 2002 6:51 pm:
 you can iterate over DTML documents using <dtml-in expr="objectValues('DTML Document')">

This code displayed the following file listing, as shown in [4-4].

Iterating over a list of files.

Figure 4-4 Iterating over a list of files.

Let's look at this DTML example step by step. First, the var tag is used to insert your common header into the document. Next, to indicate that you want the browser to draw an HTML bulleted list, you have the ul HTML tag.

Then there is the in tag. The tag has an expression that is calling the Zope API method called objectValues. This method returns a sequence of objects in the current folder that match a given criteria. In this case, the objects must be files. This method call will return a list of files in the current folder.

The in tag will loop over every item in this sequence. If there are four file objects in the current folder, then the in tag will execute the code in its block four times; once for each object in the sequence.

Anonymous User - June 10, 2002 10:27 am:
 link to Chapter 8?

During each iteration, the in tag looks for variables in the current object, first. In Chapter 8, "Variables and Advanced DTML" we'll look more closely at how DTML looks up variables.

Anonymous User - Sep. 21, 2002 9:44 pm:
 For each iteration, before executing the block (better: body) of the in-tag,
 the current object ist pushed onto the namespace and popped from it afterwards.
 Therefore variables are looked up in the current object first.

For example, this in tag iterates over a collection of File objects and uses the var tag to look up variables in each file:


<dtml-in expr="objectValues('File')">
  <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></li>
</dtml-in>

The first var tag is an entity and the second is a normal DTML var tag. When the in tag loops over the first object its absolute_url and title_or_id variables will be inserted in the first bulleted list item:


<ul>
  <li><a href="http://localhost:8080/FirstFile">FirstFile</a></li>

During the second iteration the second object's absolute_url and title_or_id variables are inserted in the output:


<ul>
  <li><a href="http://localhost:8080/FirstFile">FirstFile</a></li>
  <li><a href="http://localhost:8080/SecondFile">SecondFile</a></li>

This process will continue until the in tag has iterated over every file in the current folder. After the in tag you finally close your HTML bulleted list with a closing ul HTML tag and the standard_html_footer is inserted to close the document.

In Tag Special Variables

The in tag provides you with some useful information that lets you customize your HTML while you are iterating over a sequence. For example, you can make your file library easier to read by putting it in an HTML table and making every other table row an alternating color, like this, as shown in [4-5].

File listing with alternating row colors.

Figure 4-5 File listing with alternating row colors.

The in tag makes this easy. Change your file library method a bit to look like this:


<dtml-var standard_html_header>

<table>
<dtml-in expr="objectValues('File')">
  <dtml-if sequence-even>
    <tr bgcolor="grey">
  <dtml-else>
    <tr>
  </dtml-if>    
  <td>
  <a href="&dtml-absolute_url;"><dtml-var title_or_id></a>
  </td></tr>
</dtml-in>
</table>

<dtml-var standard_html_footer>
Anonymous User - Sep. 9, 2002 7:09 pm:
 Cool!  I've wondered about how to do this.

Here an if tag is used to test for a special variable called sequence-even. The in tag sets this variable to a true or false value each time through the loop. If the current iteration number is even, then the value is true, if the iteration number is odd, it is false.

The result of this test is that a tr tag with either a gray background or no background is inserted into the document for every other object in the sequence. As you might expect, there is a sequence-odd that always has the opposite value of sequence-even.

There are many special variables that the

in

tag defines for you. Here are the most common and useful:

sequence-item
This special variable is the current item in the iteration.

In the case of the file library example, each time through the loop the current file of the iteration is assigned to sequence-item. It is often useful to have a reference to the current object in the iteration.

sequence-index
the current number, starting from 0, of iterations completed so far. If this number is even, sequence-even is true and sequence-odd is false.

sequence-number
The current number, starting from 1, of iterations completed so far. This can be thought of as the cardinal position (first, second, third, etc.) of the current object in the loop. If this number is even, sequence-even is false and sequence-odd is true.

sequence-start
This variable is true for the very first iteration.

sequence-end
This variable is true for the very last iteration.

kaleissin - May 16, 2002 2:35 pm:
 dtml-in is a nice way to shoot yourself in the foot and make the page take ages to render. If you find
yourself using the sequence-<foo> stuff about ten times or more in a single page/method/loop-struct,
rethink
 the problem and/or consider using a Python/Perl script or go for an External method/script... You'll be
 grateful you did when the thing needs to be changed or speeded up :)

These special variables are detailed more thoroughly in Appendix A.

DTML is a powerful tool for creating dynamic content. It allows you to perform fairly complex calculations. In Chapter 8, "Variables and Advanced DTML", you'll find out about many more DTML tags, and more powerful ways to use the tags you already have seen. Despite its power, you should resist the temptation to use DTML for complex scripting. In Chapter 10, "Advanced Zope Scripting" you'll find out about how to use Python and Perl for scripting business logic.

Anonymous User - June 10, 2002 5:40 pm:
 links to Appendis A and Chapter 10?
Anonymous User - June 14, 2002 6:48 am:
 Why do you always comment that links are needed? At the top and bottom of every page is an "up botton" that
 links to the table of contents where the reader may jump to any chapter. Linking to other chapters and
 appendices 30 times within each chapter will only make the document more confusing to read, as it would lead
 the reader to go through the manual out of sequence.
Anonymous User - July 25, 2002 8:10 pm:
 I agree, links to chapters are mostly useless, however, links to specific sections of certain chapters which
directly expand on the recent content are very useful in my humble opinion. This is especially true for those
 who are on their second pass through the documentation, and are wishing merely to refresh their memory on
specific areas in a 'basic to advanced or overview to specific' manner. I only make this comment to further a
 personal desire to see more of the latter types of links.
krump - Aug. 27, 2002 12:13 am:
 I'll concur on adding links to specific chapters. It is just a personal preference though. Some people might
 hate having lots of little links littered all over.
Anonymous User - Oct. 17, 2002 6:32 am:
 most examples in this page just don't work
 thanks to contibutors comments they do after some changes
 but this is quite a hard start with zope
Anonymous User - Jan. 21, 2003 7:57 am:
 I have spread too much time in learning simple things, this is negative.Thanks to contributors comments

Previous Page Up one Level Next Page Dynamic Content with DTML Comments On/Off Table of Contents