[Checkins] SVN: zope2book/trunk/ Move dtml chapters back into the book

Hanno Schlichting plone at hannosch.info
Mon Feb 16 13:00:16 EST 2009


Log message for revision 96595:
  Move dtml chapters back into the book
  

Changed:
  D   zope2book/trunk/old/
  A   zope2book/trunk/source/AdvDTML.rst
  A   zope2book/trunk/source/DTML.rst
  U   zope2book/trunk/source/Preface.rst
  U   zope2book/trunk/source/index.rst

-=-
Copied: zope2book/trunk/source/AdvDTML.rst (from rev 96594, zope2book/trunk/old/AdvDTML.rst)
===================================================================
--- zope2book/trunk/source/AdvDTML.rst	                        (rev 0)
+++ zope2book/trunk/source/AdvDTML.rst	2009-02-16 18:00:15 UTC (rev 96595)
@@ -0,0 +1,1664 @@
+Advanced DTML
+=============
+
+DTML is the kind of language that appears to "do what you mean."
+That is good when it does what you actually want it to do, but when
+it does something you don't want to do, well, it's no fun at all.
+This chapter tells you how to make DTML do what you *really* mean.
+When you're done reading this chapter you will be able to write DTML
+that will accomplish a number of complex tasks including:
+
+- Inspect and Modify the REQUEST object
+
+- Modify the current namespace
+
+- Call other scripts from within DTML
+
+- Send email with or without MIME attachments
+
+- Handle exceptions within DTML    
+
+A few of caveats before getting started:
+
+- It's a good idea to know something about Python before diving into
+  advanced DTML or any other advanced area of Zope.
+
+- Understand the Zope acquisition model and how it works.
+
+- If you are writing very complex functionality in DTML, consider
+  using a Python Script.  This will ease maintenance, not to mention
+  readability.
+
+- Understand the difference between a DTML Document and a DTML
+  Method before embarking on building a huge site. See the explanation
+  included in this chapter.
+
+It's no lie that DTML has a reputation for complexity.  While it is true
+that DTML is really simple if all you want to do is simple layout,
+using DTML for more advanced tasks requires an understanding of where 
+DTML variables come from.
+
+Here's a very tricky error that almost all newbies encounter.
+Imagine you have a DTML Document called *zooName*.  This
+document contains an HTML form like the following::
+
+  <dtml-var standard_html_header>
+
+    <dtml-if zooName>
+
+      <p><dtml-var zooName></p>
+
+    <dtml-else>
+
+      <form action="<dtml-var URL>" method="GET">
+        <input name="zooName">
+        <input type="submit" value="What is zooName?">
+      </form>
+
+    </dtml-if>  
+
+  <dtml-var standard_html_footer>
+
+This looks simple enough, the idea is, this is an HTML page that calls
+itself.  This is because the HTML action is the *URL* variable, which
+will become the URL of the DTML Document.  
+
+If there is a 'zooName' variable, then the page will print it, if there
+isn't, it shows a form that asks for it.  When you click submit, the data
+you enter will make the "if" evaluate to true, and this code should print
+what was entered in the form.
+
+But unfortunately, this is one of those instances where DTML will not do
+what you mean, because the name of the DTML Document that contains this
+DTML is also named *zooName*, and it doesn't use the variable out of the
+request, it uses itself, which causes it to call itself and call itself, ad
+infinitum, until you get an "excessive recursion" error.  So instead of
+doing what you really meant, you got an error. This is what confuses
+beginners.  In the next couple of sections, we'll show you how to fix this
+example to do what you mean.
+
+How Variables are Looked up
+---------------------------
+
+There are actually two ways to fix the DTML error in the
+*zooName* document.  The first is that you can rename the document
+to something like *zopeNameFormOrReply* and always remember this
+special exception and never do it; never knowing why it happens.
+The second is to understand how names are looked up, and to be
+explicit about where you want the name to come from in the
+*namespace*.
+
+The DTML namespace is a collection of objects arranged in a *stack*.  A
+stack is a list of objects that can be manipulated by *pushing* and
+*popping* objects on to and off of the stack. 
+
+When a DTML Document or DTML Method is executed, Zope creates a
+DTML namespace to resolve DTML variable names. It's important to
+understand the workings of the DTML namespace so that you can
+accurately predict how Zope will locate variables. Some of the
+trickiest problems you will run into with DTML can be resolved by
+understanding the DTML namespace.
+
+When Zope looks for names in the DTML namespace stack it first looks at
+the topmost object in the stack.  If the name can't be found
+there, then the next item down is introspected.  Zope will work its way
+down the stack, checking each object in turn until it finds the name
+that it is looking for.
+
+If Zope gets all the way down to the bottom of the stack and
+can't find what it is looking for, then an error is generated.  For
+example, try looking for the non-existent name, *unicorn*::
+
+  <dtml-var unicorn>
+
+As long as there is no variable named *unicorn* viewing this
+DTML will return an error, as shown in the figure below.
+
+.. figure:: ../Figures/7-1.png
+
+   DTML error message indicating that it cannot find a variable
+
+But the DTML stack is not all there is to names because DTML
+doesn't start with an empty stack, before you even begin executing
+DTML in Zope there are already a number of objects pushed on the
+namespace stack.
+
+DTML Namespaces
+---------------
+
+DTML namespaces are built dynamically for every request in Zope. When
+you call a DTML Method or DTML Document through the web, the DTML
+namespace starts with the same first two stack elements; the client
+object and the request, as shown in the figure below.
+
+.. figure:: ../Figures/7-2.png
+
+   Initial DTML namespace stack
+
+The client object is the first object on the top of the DTML namespace
+stack when entering a transaction (note:  commands exist to push 
+additional parameters onto the namespace stack during a thread of 
+execution).  What the client object is depends on whether you are
+executing a DTML Method or a DTML Document.  In our example above, this
+means that the client object is named *zooName*.  Which is why it
+breaks.  The form input that we really wanted comes from the web
+request, but the client is looked at first.
+
+The request namespace is always on the bottom of the DTML namespace
+stack, and is therefore the last namespace to be looked in for names.
+This means that we must be explicit in our example about which
+namespace we want.  We can do this with the DTML 'with' tag::
+
+  <dtml-var standard_html_header>
+
+    <dtml-with REQUEST only>
+      <dtml-if zooName>
+        <p><dtml-var zooName></p>
+      <dtml-else>
+        <form action="<dtml-var URL>" method="GET">
+          <input name="zooName">
+          <input type="submit" value="What is zooName?">
+        </form>
+      </dtml-if>
+    </dtml-with>
+
+  <dtml-var standard_html_footer>
+
+Here, the with tag says to look in the 'REQUEST' namespace, and *only*
+the 'REQUEST' namespace, for the name "zooName".
+
+DTML Client Object  
+~~~~~~~~~~~~~~~~~~
+
+The client object in DTML depends on whether or not you are executing a
+DTML Method or a DTML Document.  In the case of a Document, the client
+object is always the document itself, or in other words, a DTML
+Document is its own client object.
+
+A DTML Method however can have different kinds of client objects
+depending on how it is called.  For example, if you had a DTML Method
+that displayed all of the contents of a folder then the client object
+would be the folder that is being displayed.  This client object can
+change depending on which folder the method in question is
+displaying.  For example, consider the following DTML Method named
+*list* in the root folder::
+
+  <dtml-var standard_html_header>
+
+  <ul>
+  <dtml-in objectValues>
+    <li><dtml-var title_or_id></li>
+  </dtml-in>
+  </ul>
+
+  <dtml-var standard_html_footer>
+
+Now, what this method displays depends upon how it is used.  If
+you apply this method to the *Reptiles* folder with the URL
+'http://localhost:8080/Reptiles/list', then you will get
+something that looks like the figure below.
+
+.. figure:: ../Figures/7-3.png
+
+   Applying the *list* method to the *Reptiles* folder
+
+But if you were to apply the method to the *Birds* folder with
+the URL *http://localhost:8080/Birds/list* then you would get
+something different, only two items in the list, *Parrot* and
+*Raptors*.
+
+Same DTML Method, different results. In the first example, the client
+object of the *list* method was the *Reptiles* folder.  In the second
+example, the client object was the *Birds* folder. When Zope looked
+up the *objectValues* variable, in the first case it called the
+*objectValues* method of the *Reptiles* folder, in the second case it
+called the *objectValues* method of the *Birds* folder.
+
+In other words, the client object is where variables such as
+methods, and properties are looked up first.
+
+As you saw in "Dynamic Content with DTML", if Zope
+cannot find a variable in the client object, it searches through
+the object's containers.  Zope uses acquisition to automatically
+inherit variables from the client object's containers.  So when
+Zope walks up the object hierarchy looking for variables it
+always starts at the client object, and works its way up from
+there.
+
+DTML Method vs. DTML Document
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the most potentially confusing choices to make for Zope
+newbies is the choice between a DTML Method and a DTML Document.
+Unfortunately, many Zope newbies develop entire sites using one 
+type of object only to discover that they should have used the 
+other type. In general, keep the following items in mind when 
+deciding upon which type to use:
+
+- **Does the object require properties of its own?** If so,
+    use a DTML Document since DTML Methods have no inherent
+    properties.
+
+- **Does the object need to be called as a "page"?** If so,
+    consider using a DTML Document since it will be easier
+    to control such items as page title by using properties.
+
+- **Does the object need transparency to its context?** If so, 
+    you should probably use a DTML Method since these objects
+    act as though they are directly attached to their calling, 
+    or containing object.
+
+DTML Request Object
+~~~~~~~~~~~~~~~~~~~
+
+The request object is the bottom object on the DTML
+namespace stack.  The request contains all of the information
+specific to the current web request.
+
+Just as the client object uses acquisition to look in a number
+of places for variables, so too the request looks up variables
+in a number of places. When the request looks for a variable it
+consults these sources in order:
+
+1. The CGI environment. The `Common Gateway Interface
+   <http://www.w3.org/CGI/>`_, or CGI interface defines
+   a standard set of environment variables to be used by
+   dynamic web scripts.  These variables are provided by Zope
+   in the REQUEST namespace.
+
+2. Form data. If the current request is a form action, then
+   any form input data that was submitted with the request can
+   be found in the REQUEST object.
+
+3. Cookies. If the client of the current request has any cookies
+   these can be found in the current REQUEST object.
+
+4. Additional variables. The REQUEST namespace provides you
+   with lots of other useful information, such as the URL of
+   the current object and all of its parents.
+
+The request namespace is very useful in Zope since it is the
+primary way that clients (in this case, web browsers)
+communicate with Zope by providing form data, cookies and other
+information about themselves. For more information about the
+request object, see Appendix B.
+
+A very simple and enlightening example is to simply render the REQUEST
+object in a DTML Document or Method::
+
+  <dtml-var standard_html_header>
+
+  <dtml-var REQUEST>
+
+  <dtml-var standard_html_footer>
+
+Try this yourself, you should get something that looks like
+the figure below.
+
+.. figure:: ../Figures/7-4.png
+
+   Displaying the request
+
+Since the request comes after the client object, if there are names
+that exist in both the request and the client object, DTML will
+always find them first in the client object. This can be a
+problem. Next, let's look at some ways to get around this problem by
+controlling more directly how DTML looks up variables.
+
+Rendering Variables
+-------------------
+
+When you insert a variable using the *var* tag, Zope first looks
+up the variable using the DTML namespace, it then *renders* it
+and inserts the results. Rendering means turning an object or
+value into a string suitable for inserting into the output. Zope
+renders simple variables by using Python's standard method for
+coercing objects to strings. For complex objects such as DTML
+Methods and SQL Methods, Zope will call the object instead of
+just trying to turn it into a string. This allows you to insert
+DTML Methods into other DTML Methods.
+
+In general Zope renders variables in the way you would
+expect. It's only when you start doing more advanced tricks that
+you become aware of the rendering process. Later in this chapter
+we'll look at some examples of how to control rendering using
+the 'getitem' DTML utility function.
+
+Modifying the DTML Namespace
+----------------------------
+
+Now that you know the DTML namespace is a stack, you may
+be wondering how, or even why, new objects get pushed onto it.
+
+Some DTML tags modify the DTML namespace while they are executing.
+A tag may push some object onto the namespace stack during the
+course of execution.  These tags include the *in* tag, the *with*
+tag, and the *let* tag.
+
+*In* Tag Namespace Modifications
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When the *in* tag iterates over a sequence it pushes the current
+item in the sequence onto the top of the namespace stack::
+
+  <dtml-var getId> <!-- This is the id of the client object -->
+
+  <dtml-in objectValues>
+
+    <dtml-var getId> <!-- this is the id of the current item in the 
+                       objectValues sequence -->
+  </dtml-in>
+
+You've seen this many times throughout the examples in this
+book.  While the *in* tag is iterating over a sequence, each item
+is pushed onto the namespace stack for the duration of the
+contents of the in tag block.  When the block is finished
+executing, the current item in the sequence is popped off the
+DTML namespace stack and the next item in the sequence is pushed
+on.
+
+Additional Notes
+%%%%%%%%%%%%%%%%
+
+To be more accurate, the *in* tag pushes a number of items
+onto the namespace stack.  These include sequence variables,
+grouping variables, and batch variables in addition to the
+object itself.  Some of those variables are:
+
+- sequence-item: The current item within the iteration.
+
+- sequence-start: True if the current item is the first item
+  in the sequence.
+
+- sequence-end: True if the current item is the last item in
+   the sequence.
+
+- sequence-length: The length of the sequence. 
+
+- previous-sequence: True on the first iteration if the
+  current batch is not the first one. Batch size is set with the
+  size attribute.
+
+- next-sequence: True on the last iteration if the current
+  batch is not the last batch.
+
+There are many more variables available when using the *in*
+tag.  See `Appendix A <AppendixA.html>`_ for more detail.
+
+The *With* Tag
+~~~~~~~~~~~~~~
+
+The *with* tag pushes an object that you specify onto 
+the namespace stack for the duration of the with block. This
+allows you to specify where variables should be looked up first.
+When the with block closes, the object is popped off the
+namespace stack.
+
+Consider a folder that contains a bunch of methods and
+properties that you are interested in.  You could access those
+names with Python expressions like this::
+
+  <dtml-var standard_html_header>
+
+  <dtml-var expr="Reptiles.getReptileInfo()">
+  <dtml-var expr="Reptiles.reptileHouseMaintainer">
+
+  <dtml-in expr="Reptiles.getReptiles()">
+    <dtml-var species>
+  </dtml-in>
+
+  <dtml-var standard_html_footer>
+
+Notice that a lot of complexity is added to the code just to get
+things out of the *Reptiles* folder. Using the *with* tag you can
+make this example much easier to read::
+
+  <dtml-var standard_html_header>
+
+  <dtml-with Reptiles>
+
+    <dtml-var getReptileInfo>
+    <dtml-var reptileHouseMaintainer>
+
+    <dtml-in getReptiles>
+      <dtml-var species>
+    </dtml-in>
+
+  </dtml-with>
+
+  <dtml-var standard_html_footer>
+
+Another reason you might want to use the *with* tag is to put the
+request, or some part of the request on top of the namespace
+stack. For example suppose you have a form that includes an input
+named *id*. If you try to process this form by looking up the
+*id* variable like so::
+
+  <dtml-var id>
+
+You will not get your form's id variable, but the client
+object's id. One solution is to push the web request's form on
+to the top of the DTML namespace stack using the *with* tag::
+
+  <dtml-with expr="REQUEST.form">
+    <dtml-var id>
+  </dtml-with>
+
+This will ensure that you get the form's id first. See Appendix
+B for complete API documentation of the request object.
+
+If you submit your form without supplying a value for the *id* input,
+the form on top of the namespace stack will do you no good, since the
+form doesn't contain an *id* variable. You'll still get the client
+object's id since DTML will search the client object after failing to
+find the *id* variable in the form. The *with* tag has an attribute
+that lets you trim the DTML namespace to only include the object you
+pushed onto the namespace stack::
+
+  <dtml-with expr="REQUEST.form" only>
+    <dtml-if id>
+      <dtml-var id>
+    <dtml-else>
+      <p>The form didn't contain an "id" variable.</p>
+    </dtml-if>
+  </dtml-with>
+
+Using the *only* attribute allows you to be sure about where
+your variables are being looked up.
+
+The *Let* Tag
+~~~~~~~~~~~~~
+
+The *let* tag lets you push a new namespace onto the namespace stack.
+This namespace is defined by the tag attributes to the *let* tag::
+
+  <dtml-let person="'Bob'" relation="'uncle'">
+    <p><dtml-var person>'s your <dtml-var relation>.</p>
+  </dtml-let>
+
+This would display::
+
+  <p>Bob's your uncle.</p>
+
+The *let* tag accomplishes much of the same goals as the *with*
+tag. The main advantage of the let tag is that you can use it to
+define multiple variables to be used in a block. The *let* tag
+creates one or more new name-value pairs and pushes a
+namespace object containing those variables and their values on
+to the top of the DTML namespace stack. In general the *with*
+tag is more useful to push existing objects onto the namespace
+stack, while the *let* tag is better suited for defining new
+variables for a block.
+
+When you find yourself writing complex DTML that requires things
+like new variables, there's a good chance that you could do the
+same thing better with Python or Perl. Advanced scripting is
+covered in the chapter entitled `Advanced Zope Scripting
+<ScriptingZope.html>`_ .
+
+The DTML namespace is a complex place, and this complexity evolved
+over a lot of time.  Although it helps to understand where names come
+from, it is much more helpful to always be specific about where you
+are looking for a name.  The 'with' and 'let' tags let you alter
+the namespace in order to obtain references to the objects you
+need.
+
+DTML Namespace Utility Functions 
+--------------------------------
+
+Like all things in Zope, the DTML namespace is an object, and it can
+be accessed directly in DTML with the *_* (underscore) object.  The
+*_* namespace is often referred to as "the under namespace".
+
+The under namespace provides you with many useful methods for certain
+programming tasks.  Let's look at a few of them.
+
+Say you wanted to print your name three times.  This can be done
+with the *in* tag, but how do you explicitly tell the *in* tag to
+loop three times?  Just pass it a sequence with three items::
+
+  <dtml-var standard_html_header>
+
+  <ul>
+  <dtml-in expr="_.range(3)">
+    <li><dtml-var sequence-item>: My name is Bob.</li>
+  </dtml-in>
+  </ul>
+
+  <dtml-var standard_html_footer>
+
+The '_.range(3)' Python expression will return a sequence of the
+first three integers, 0, 1, and 2.  The *range* function is a
+*standard Python built-in* and many of Python's built-in functions
+can be accessed through the *_* namespace, including:
+
+'range([start,], stop, [step])'
+  Returns a list of integers
+  from 'start' to 'stop' counting 'step' integers at a
+  time. 'start' defaults to 0 and 'step' defaults to 1.  For example:
+
+'_.range(3,10,2)'
+    gives '[3,5,7,9]'.
+
+'_.len(sequence)'
+  'len' returns the size of *sequence* as an integer.
+
+Many of these names come from the Python language, which contains
+a set of special functions called 'built-ins'.  The Python
+philosophy is to have a small number of built-in names.  The Zope
+philosophy can be thought of as having a large, complex array of
+built-in names.
+
+The under namespace can also be used to explicitly control variable
+look up.  There is a very common usage of this syntax.  As mentioned 
+above the in tag defines a number of special variables, like
+*sequence-item* and *sequence-key* that you can use inside a loop to
+help you display and control it.  What if you wanted to use one of
+these variables inside a Python expression?::
+
+  <dtml-var standard_html_header>
+
+  <h1>The squares of the first three integers:</h1>
+  <ul>
+  <dtml-in expr="_.range(3)">
+    <li>The square of <dtml-var sequence-item> is: 
+      <dtml-var expr="sequence-item * sequence-item">
+    </li>
+  </dtml-in>  
+  </ul>  
+
+  <dtml-var standard_html_footer>
+
+Try this, does it work?  No!  Why not?  The problem lies in this
+var tag::
+
+  <dtml-var expr="sequence-item * sequence-item">
+
+Remember, everything inside a Python expression attribute must be
+a *valid Python expression*.  In DTML, *sequence-item* is the name
+of a variable, but in Python this means "The object *sequence*
+minus the object *item*".  This is not what you want.
+
+What you really want is to look up the variable *sequence-item*.
+One way to solve this problem is to use the *in* tag *prefix*
+attribute. For example::
+
+  <dtml-var standard_html_header>
+
+  <h1>The squares of the first three integers:</h1>
+  <ul>
+  <dtml-in prefix="loop" expr="_.range(3)">
+    <li>The square of <dtml-var loop_item> is: 
+      <dtml-var expr="loop_item * loop_item">
+    </li>
+  </dtml-in>  
+  </ul>  
+
+  <dtml-var standard_html_footer>   
+
+The *prefix* attribute causes *in* tag variables to be renamed
+using the specified prefix and underscores, rather than using
+"sequence" and dashes. So in this example, "sequence-item" becomes
+"loop_item". See Appendix A for more information on the *prefix*
+attribute.
+
+Another way to look up the variable *sequence-item* in a DTML
+expression is to use the *getitem* utility function to explicitly
+look up a variable::
+
+  The square of <dtml-var sequence-item> is:
+  <dtml-var expr="_.getitem('sequence-item') * 
+                  _.getitem('sequence-item')">
+
+The *getitem* function takes the name to look up as its first
+argument. Now, the DTML Method will correctly display the square of the
+first three integers.  The *getitem* method takes an optional second
+argument which specifies whether or not to render the variable. Recall
+that rendering a DTML variable means turning it into a string. By
+default the *getitem* function does not render a variable.
+
+Here's how to insert a rendered variable named *myDoc*::
+
+  <dtml-var expr="_.getitem('myDoc', 1)">
+
+This example is in some ways rather pointless, since it's the
+functional equivalent to::
+
+  <dtml-var myDoc>
+
+However, suppose you had a form in which a user got to select
+which document they wanted to see from a list of choices. Suppose
+the form had an input named *selectedDoc* which contained the name
+of the document. You could then display the rendered document like
+so::
+
+  <dtml-var expr="_.getitem(selectedDoc, 1)">
+
+Notice in the above example that *selectedDoc* is not in
+quotes. We don't want to insert the text *selectedDoc*
+we want to insert the value of the variable named *selectedDoc*. For
+example, the value of *selectedDoc* might be 'chapterOne'. Using this
+method, you can look up an item using a dynamic value instead of 
+static text.
+
+If you are a python programmer and you begin using the more
+complex aspects of DTML, consider doing a lot of your work in
+Python scripts that you call *from* DTML.  This is explained more
+in the chapter entitled `Advanced Zope Scripting`_.
+Using Python sidesteps many of the issues in DTML.
+
+DTML Security
+-------------
+
+Zope can be used by many different kinds of users.  For example, the
+Zope site, `Zope.org <http://www.zope.org/>`_, has over 11,000 community
+members at the time of this writing.  Each member can log into Zope,
+add objects and news items, and manage their own personal area.
+
+Because DTML is a scripting language, it is very flexible about
+working with objects and their properties.  If there were no security
+system that constrained DTML then a user could potentially create
+malicious or privacy-invading DTML code.
+
+DTML is restricted by standard Zope security settings. So if you
+don't have permission to access an object by going to its URL you
+also don't have permission to access it via DTML. You can't use
+DTML to trick the Zope security system.
+
+For example, suppose you have a DTML Document named *Diary* which
+is private. Anonymous users can't access your diary via the
+web. If an anonymous user views DTML that tries to access your
+diary they will be denied::
+
+  <dtml-var Diary>
+
+DTML verifies that the current user is authorized to access all
+DTML variables.  If the user does not have authorization, then the
+security system will raise an *Unauthorized* error and the user
+will be asked to present more privileged authentication
+credentials.
+
+In the chapter entitled `Users and Security <Security.html>`_ , you
+read about security rules for executable content. There are ways
+to tailor the roles of a DTML Document or Method to allow it to
+access restricted variables regardless of the viewer's roles.
+
+Safe Scripting Limits
+---------------------
+
+DTML will not let you gobble up memory or execute infinite loops
+and recursions.  Because the restrictions on looping and memory
+use are relatively tight, DTML is not the right language for
+complex, expensive programming logic.  For example, you cannot
+create huge lists with the *_.range* utility function. You also
+have no way to access the filesystem directly in DTML.
+
+Keep in mind however that these safety limits are simple and can
+be outsmarted by a determined user.  It's generally not a good
+idea to let anyone you don't trust write DTML code on your site.
+
+Advanced DTML Tags
+------------------
+
+In the rest of this chapter we'll look at the many advanced DTML
+tags. These tags are summarized in Appendix A.  DTML has a set of
+built-in tags, as documented in this book, which can be counted on
+to be present in all Zope installations and perform the most
+common kinds of things. However, it is also possible to add new
+tags to a Zope installation. Instructions for doing this are
+provided at the Zope.org website, along with an interesting set
+of contributed DTML tags.
+
+This section covers what could be referred to as Zope
+*miscellaneous* tags.  These tags don't really fit into any broad
+categories except for one group of tags, the *exception handling*
+DTML tags which are discussed at the end of this chapter.
+
+The *Call* Tag
+--------------
+
+The *var* tag can call methods, but it also inserts the return
+value. Using the *call* tag you can call methods without inserting
+their return value into the output.  This is useful if you are
+more interested in the effect of calling a method rather than its
+return value.
+
+For example, when you want to change the value of a property,
+*animalName*, you are more interested in the effect of calling the
+*manage_changeProperties* method than the return value the method
+gives you.  Here's an example::
+
+  <dtml-if expr="REQUEST.has_key('animalName')">
+    <dtml-call expr="manage_changeProperties(animalName=REQUEST['animalName'])">
+    <h1>The property 'animalName' has changed</h1>
+  <dtml-else>
+    <h1>No properties were changed</h1>
+  </dtml-if>
+
+In this example, the page will change a property depending on whether
+a certain name exists.  The result of the *manage_changeProperties*
+method is not important and does not need to be shown to the user.
+
+Another common usage of the *call* tag is calling methods that affect
+client behavior, like the 'RESPONSE.redirect' method.  In this
+example, you make the client redirect to a different page, to
+change the page that gets redirected, change the value for the
+"target" variable defined in the *let* tag::
+
+  <dtml-var standard_html_header>
+
+  <dtml-let target="'http://example.com/new_location.html'">
+
+    <h1>This page has moved, you will now be redirected to the
+    correct location.  If your browser does not redirect, click <a
+    href="<dtml-var target>"><dtml-var target></a>.</h1>
+
+    <dtml-call expr="RESPONSE.redirect(target)">
+
+  </dtml-let>
+
+  <dtml-var standard_html_footer>  
+
+In short, the *call* tag works exactly like the *var* tag with the
+exception that it doesn't insert the results of calling the
+variable.
+
+Another possibility for use of the *call* tag would be to call a
+ZSQL Method or or preprocess the REQUEST.  Two examples of calling
+a ZSQL method::
+
+  <dtml-call "insertLogEntry(REQUEST)">
+
+or::
+
+  <dtml-call "insertLogEntry(logInfo=REQUEST.get('URL0'), severity=1)">
+
+To call a python script that might do any number of things,
+including preprocessing the REQUEST::
+
+  <dtml-call "preprocess(REQUEST)">
+
+The *Comment* Tag
+-----------------
+
+DTML can be documented with comments using the *comment* tag::
+
+  <dtml-var standard_html_header>
+
+  <dtml-comment>
+
+    This is a DTML comment and will be removed from the DTML code
+    before it is returned to the client.  This is useful for
+    documenting DTML code.  Unlike HTML comments, DTML comments
+    are NEVER sent to the client.
+
+  </dtml-comment>
+
+  <!-- 
+
+    This is an HTML comment, this is NOT DTML and will be treated
+    as HTML and like any other HTML code will get sent to the
+    client.  Although it is customary for an HTML browser to hide
+    these comments from the end user, they still get sent to the
+    client and can be easily seen by 'Viewing the Source' of a
+    document.
+
+  -->
+
+  <dtml-var standard_html_footer>        
+
+The *comment* block is removed from DTML output.
+
+In addition to documenting DTML you can use the *comment* tag to
+temporarily comment out other DTML tags. Later you can remove the
+*comment* tags to re-enable the DTML.
+
+The *Tree* Tag
+--------------
+
+The *tree* tag lets you easily build dynamic trees in HTML to
+display hierarchical data.  A *tree* is a graphical representation
+of data that starts with a "root" object that has objects
+underneath it often referred to as "branches".  Branches can have
+their own branches, just like a real tree.  This concept should be
+familiar to anyone who has used a file manager program like
+Microsoft Windows Explorer to navigate a file system.  And, in
+fact, the left hand "navigation" view of the Zope management
+interface is created using the tree tag.
+
+For example here's a tree that represents a collection of folders
+and sub-folders.
+
+.. figure:: ../Figures/7-5.png
+
+   HTML tree generated by the tree tag
+
+Here's the DTML that generated this tree display::
+
+  <dtml-var standard_html_header>
+
+  <dtml-tree>
+
+    <dtml-var getId>
+
+  </dtml-tree>
+
+  <dtml-var standard_html_footer>
+
+The *tree* tag queries objects to find their sub-objects and takes
+care of displaying the results as a tree. The *tree* tag block works
+as a template to display nodes of the tree.
+
+Now, since the basic protocol of the web, HTTP, is stateless, you
+need to somehow remember what state the tree is in every time you
+look at a page.  To do this, Zope stores the state of the tree in
+a *cookie*.  Because this tree state is stored in a cookie, only
+one tree can appear on a web page at a time, otherwise they will
+confusingly use the same cookie.
+
+You can tailor the behavior of the *tree* tag quite a bit with *tree*
+tag attributes and special variables. Here is a sampling of *tree*
+tag attributes.
+
+branches
+  The name of the method used to find sub-objects. This
+  defaults to *tpValues*, which is a method defined by a number of
+  standard Zope objects.
+
+leaves
+  The name of a method used to display objects that do
+  not have sub-object branches.
+
+nowrap
+  Either 0 or 1. If 0, then branch text will wrap to fit in
+  available space, otherwise, text may be truncated. The default
+  value is 0.
+
+sort
+  Sort branches before text insertion is performed. The
+  attribute value is the name of the attribute that items should be
+  sorted on.
+
+assume_children
+  Either 0 or 1. If 1, then all objects are
+  assumed to have sub-objects, and will therefore always have a
+  plus sign in front of them when they are collapsed. Only when an
+  item is expanded will sub-objects be looked for. This could be a
+  good option when the retrieval of sub-objects is a costly
+  process.  The defalt value is 0.
+
+single
+  Either 0 or 1. If 1, then only one branch of the tree can
+  be expanded. Any expanded branches will collapse when a new branch
+  is expanded.  The default value is 0.
+
+skip_unauthorized
+  Either 0 or 1. If 1, then no errors will be
+  raised trying to display sub-objects for which the user does not
+  have sufficient access. The protected sub-objects are not
+  displayed.  The default value is 0.
+
+Suppose you want to use the *tree* tag to create a dynamic site
+map. You don't want every page to show up in the site map. Let's
+say that you put a property on folders and documents that you want
+to show up in the site map.
+
+Let's first define a Script with the id of *publicObjects*
+that returns public objects::
+
+  ## Script (Python) "publicObjects"
+  ##
+  """
+  Returns sub-folders and DTML documents that have a
+  true 'siteMap' property.
+  """
+  results=[]
+  for object in context.objectValues(['Folder', 'DTML Document']):
+      if object.hasProperty('siteMap') and object.siteMap:
+          results.append(object)
+  return results
+
+Now we can create a DTML Method that uses the *tree* tag and our
+Scripts to draw a site map::
+
+  <dtml-var standard_html_header>
+
+  <h1>Site Map</h1>
+
+  <p><a href="&dtml-URL0;?expand_all=1">Expand All</a> |
+     <a href="&dtml-URL0;?collapse_all=1">Collapse All</a>
+  </p>
+
+  <dtml-tree branches="publicObjects" skip_unauthorized="1">
+    <a href="&dtml-absolute_url;"><dtml-var title_or_id></a>
+  </dtml-tree>
+
+  <dtml-var standard_html_footer>
+
+This DTML Method draws a link to all public resources and displays
+them in a tree. Here's what the resulting site map looks like.
+
+.. figure:: ../Figures/7-6.png
+
+   Dynamic site map using the tree tag
+
+For a summary of the *tree* tag arguments and special variables see
+Appendix A.
+
+The *Return* Tag
+----------------
+
+In general DTML creates textual output. You can however, make DTML
+return other values besides text. Using the *return* tag you can
+make a DTML Method return an arbitrary value just like a Python or
+Perl-based Script.
+
+Here's an example::
+
+  <p>This text is ignored.</p>
+
+  <dtml-return expr="42">
+
+This DTML Method returns the number 42.
+
+Another upshot of using the *return* tag is that DTML execution
+will stop after the *return* tag.
+
+If you find yourself using the *return* tag, you almost certainly
+should be using a Script instead. The *return* tag was developed
+before Scripts, and is largely useless now that you can easily
+write scripts in Python and Perl.
+
+The *Sendmail* Tag
+------------------
+
+The *sendmail* tag formats and sends a mail messages. You can use
+the *sendmail* tag to connect to an existing Mail Host, or you can
+manually specify your SMTP host.
+
+Here's an example of how to send an email message with the
+*sendmail* tag::
+
+  <dtml-sendmail>
+  To: <dtml-var recipient>
+  From: <dtml-var sender>
+  Subject: Make Money Fast!!!!
+
+  Take advantage of our exciting offer now! Using our exclusive method
+  you can build unimaginable wealth very quickly. Act now!
+  </dtml-sendmail>
+
+Notice that there is an extra blank line separating the mail
+headers from the body of the message.
+
+A common use of the *sendmail* tag is to send an email message
+generated by a feedback form. The *sendmail* tag can contain any
+DTML tags you wish, so it's easy to tailor your message with form
+data.
+
+The *Mime* Tag
+--------------
+
+The *mime* tag allows you to format data using MIME (Multipurpose
+Internet Mail Extensions). MIME is an Internet standard for
+encoding data in email message. Using the *mime* tag you can use
+Zope to send emails with attachments.
+
+Suppose you'd like to upload your resume to Zope and then have Zope
+email this file to a list of potential employers.
+
+Here's the upload form::
+
+  <dtml-var standard_html_header>
+
+  <p>Send you resume to potential employers</p>
+
+  <form method=post action="sendresume" ENCTYPE="multipart/form-data">
+  <p>Resume file: <input type="file" name="resume_file"></p>
+  <p>Send to:</p>
+  <p>
+  <input type="checkbox" name="send_to:list" value="jobs at yahoo.com">
+    Yahoo<br>
+
+  <input type="checkbox" name="send_to:list" value="jobs at microsoft.com">
+    Microsoft<br>
+
+  <input type="checkbox" name="send_to:list" value="jobs at mcdonalds.com">
+    McDonalds</p>
+
+  <input type=submit value="Send Resume">
+  </form>
+
+  <dtml-var standard_html_footer>
+
+Note:  The text *:list* added to the name of the input fields directs 
+Zope to treat the received information as a list type. For example if 
+the first two checkboxes were selected in the above upload form, the 
+REQUEST variable send_to would have the value [jobs at yahoo.com, jobs at microsoft.com]
+
+Create another DTML Method called *sendresume* to process the form
+and send the resume file::
+
+  <dtml-var standard_html_header>
+
+  <dtml-if send_to>
+
+    <dtml-in send_to> 
+
+      <dtml-sendmail smtphost="my.mailserver.com">
+      To: <dtml-var sequence-item>
+      Subject: Resume
+      <dtml-mime type=text/plain encode=7bit>
+
+      Hi, please take a look at my resume.
+
+      <dtml-boundary type=application/octet-stream disposition=attachment 
+      encode=base64><dtml-var expr="resume_file.read()"></dtml-mime>
+      </dtml-sendmail>
+
+    </dtml-in>
+
+    <p>Your resume was sent.</p>
+
+  <dtml-else>
+
+    <p>You didn't select any recipients.</p>
+
+  </dtml-if>
+
+  <dtml-var standard_html_footer>    
+
+This method iterates over the *sendto* variable and sends one
+email for each item.
+
+Notice that there is no blank line between the 'To:' header and
+the starting *mime* tag.  If a blank line is inserted between them
+then the message will not be interpreted as a *multipart* message
+by the receiving mail reader.
+
+Also notice that there is no newline between the *boundary* tag
+and the *var* tag, or the end of the *var* tag and the closing
+*mime* tag.  This is important, if you break the tags up with
+newlines then they will be encoded and included in the MIME part,
+which is probably not what you're after.
+
+As per the MIME spec, *mime* tags may be nested within *mime* tags
+arbitrarily.
+
+The *Unless* Tag
+----------------
+
+The *unless* tag executes a block of code unless the given condition is
+true. The *unless* tag is the opposite of the *if* tag.  The DTML
+code::
+
+  <dtml-if expr="not butter">
+    I can't believe it's not butter.
+  </dtml-if>
+
+is equivalent to::
+
+  <dtml-unless expr="butter">
+    I can't believe it's not butter.
+  </dtml-unless>
+
+What is the purpose of the *unless* tag? It is simply a convenience
+tag. The *unless* tag is more limited than the *if* tag, since it
+cannot contain an *else* or *elif* tag.
+
+Like the *if* tag, calling the *unless* tag by name does existence
+checking, so::
+
+  <dtml-unless the_easter_bunny>
+    The Easter Bunny does not exist or is not true.
+  </dtml-unless>
+
+Checks for the existence of *the_easter_bunny* as well as its
+truth. While this example only checks for the truth of
+*the_easter_bunny*::
+
+  <dtml-unless expr="the_easter_bunny">
+    The Easter Bunny is not true.
+  </dtml-unless>
+
+This example will raise an exception if *the_easter_bunny* does not
+exist.
+
+Anything that can be done by the *unless* tag can be done by the
+*if* tag.  Thus, its use is totally optional and a matter of
+style.
+
+Batch Processing With The *In* Tag
+----------------------------------
+
+Often you want to present a large list of information but only
+show it to the user one screen at a time.  For example, if a
+user queried your database and got 120 results, you will probably
+only want to show them to the user a small batch, say 10 or 20
+results per page.  Breaking up large lists into parts is called
+*batching*. Batching has a number of benefits.
+
+  o The user only needs to download a reasonably sized document
+  rather than a potentially huge document. This makes pages load
+  faster since they are smaller.
+
+  o Because smaller batches of results are being used, often less
+  memory is consumed by Zope.
+
+  o *Next* and *Previous* navigation interfaces makes scanning
+  large batches relatively easy.
+
+The *in* tag provides several variables to facilitate batch
+processing.  Let's look at a complete example that shows how to
+display 100 items in batches of 10 at a time::
+
+  <dtml-var standard_html_header>
+
+    <dtml-in expr="_.range(100)" size=10 start=query_start>
+
+      <dtml-if sequence-start>
+
+        <dtml-if previous-sequence>
+          <a href="<dtml-var URL><dtml-var sequence-query
+             >query_start=<dtml-var previous-sequence-start-number>">
+             (Previous <dtml-var previous-sequence-size> results)
+          </a>
+        </dtml-if>
+
+        <h1>These words are displayed at the top of a batch:</h1>
+        <ul>
+
+      </dtml-if>
+
+        <li>Iteration number: <dtml-var sequence-item></li>
+
+      <dtml-if sequence-end>
+
+        </ul>
+        <h4>These words are displayed at the bottom of a batch.</h4>
+
+        <dtml-if next-sequence>
+           <a href="<dtml-var URL><dtml-var sequence-query
+              >query_start=<dtml-var
+              next-sequence-start-number>">
+           (Next <dtml-var next-sequence-size> results)
+           </a>
+
+        </dtml-if>
+
+      </dtml-if>
+
+    </dtml-in>
+
+  <dtml-var standard_html_footer>
+
+Let's take a look at the DTML to get an idea of what's going
+on. First we have an *in* tag that iterates over 100 numbers that
+are generated by the *range* utility function. The *size*
+attribute tells the *in* tag to display only 10 items at a
+time. The *start* attribute tells the *in* tag which item number
+to display first.
+
+Inside the *in* tag there are two main *if* tags. The first one
+tests special variable 'sequence-start'. This variable is only
+true on the first pass through the in block. So the contents of
+this if tag will only be executed once at the beginning of the
+loop. The second *if* tag tests for the special variable
+'sequence-end'. This variable is only true on the last pass
+through the *in* tag. So the second *if* block will only be
+executed once at the end.  The paragraph between the *if* tags is
+executed each time through the loop.
+
+Inside each *if* tag there is another *if* tag that check for the
+special variables 'previous-sequence' and 'next-sequence'. The
+variables are true when the current batch has previous or further
+batches respectively. In other words 'previous-sequence' is true
+for all batches except the first, and 'next-sequence' is true for
+all batches except the last. So the DTML tests to see if there are
+additional batches available, and if so it draws navigation links.
+
+The batch navigation consists of links back to the document with a
+*query_start* variable set which indicates where the *in* tag should
+start when displaying the batch. To better get a feel for how this
+works, click the previous and next links a few times and watch how
+the URLs for the navigation links change.
+
+Finally some statistics about the previous and next batches are
+displayed using the 'next-sequence-size' and
+'previous-sequence-size' special variables.  All of this ends up
+generating the following HTML code::
+
+  <html>
+  <head><title>Zope</title>
+  </head>
+  <body bgcolor="#FFFFFF">
+
+    <h1>These words are displayed at the top of a batch:</h1>
+    <ul>
+      <li>Iteration number: 0</li>
+      <li>Iteration number: 1</li>
+      <li>Iteration number: 2</li>
+      <li>Iteration number: 3</li>
+      <li>Iteration number: 4</li>
+      <li>Iteration number: 5</li>
+      <li>Iteration number: 6</li>
+      <li>Iteration number: 7</li>
+      <li>Iteration number: 8</li>
+      <li>Iteration number: 9</li>
+    </ul>
+    <h4>These words are displayed at the bottom of a batch.</h4>
+
+       <a href="http://pdx:8090/batch?query_start=11">
+         (Next 10 results)
+       </a>
+
+  </body>
+  </html>
+
+Another example utilizes the commonly accepted navigation scheme
+of presenting the the user page numbers from which to select::
+
+   <dtml-in "_.range(1,101) "size=10 start=start>
+             <dtml-if sequence-start>
+               <p>Pages: 
+               <dtml-call "REQUEST.set('actual_page',1)">
+               <dtml-in previous-batches mapping>   
+                 <a href="<dtml-var URL><dtml-var sequence-query>start=<dtml-var "_['batch-start-index']+1">">
+                 <dtml-var sequence-number></a>&nbsp;
+                 <dtml-call "REQUEST.set('actual_page',_['sequence-number']+1)">     
+               </dtml-in>
+               <b><dtml-var "_['actual_page']"></b>  
+             </dtml-if>
+             <dtml-if sequence-end>
+               <dtml-in next-batches mapping>&nbsp;
+                  <a href="<dtml-var URL><dtml-var sequence-query>start=<dtml-var "_['batch-start-index']+1">">
+                  <dtml-var "_['sequence-number']+_['actual_page']"></a>
+                </dtml-in>
+             </dtml-if>
+    </dtml-in>
+
+    <dtml-in "_.range(1,101) "size=10 start=start>
+              <br><dtml-var sequence-item>
+    </dtml-in>      
+
+This quick and easy method to display pages is a nice navigational tool
+for larger batches.  It does present the drawback of having to utilize
+an additional *dtml-in* tag to iterate through the actual items, however.
+
+Batch processing can be complex. A good way to work with batches
+is to use the Searchable Interface object to create a batching
+search report for you. You can then modify the DTML to fit your
+needs.  This is explained more in the chapter entitled `Searching
+and Categorizing Content <SearchingZCatalog.html>`_.
+
+Exception Handling Tags
+-----------------------
+
+Zope has extensive exception handling facilities. You can get
+access to these facilities with the *raise* and *try* tags. For more
+information on exceptions and how they are raised and handled see
+a book on Python or you can read the online `Python
+Tutorial <http://www.python.org/doc/current/tut/node10.html>`_.
+
+The *Raise* Tag
+~~~~~~~~~~~~~~~
+
+You can raise exceptions with the *raise* tag. One reason to raise
+exceptions is to signal an error. For example you could check
+for a problem with the *if* tag, and in case there was something
+wrong you could report the error with the *raise* tag.
+
+The *raise* tag has a type attribute for specifying an error type.
+The error type is a short descriptive name for the error. In
+addition, there are some standard error types, like
+*Unauthorized* and *Redirect* that are returned as HTTP
+errors. *Unauthorized* errors cause a log-in prompt to be
+displayed on the user's browser. You can raise HTTP errors to
+make Zope send an HTTP error. For example::
+
+  <dtml-raise type="404">Not Found</dtml-raise>
+
+This raises an HTTP 404 (Not Found) error. Zope responds by
+sending the HTTP 404 error back to the client's browser.
+
+The *raise* tag is a block tag. The block enclosed by the
+*raise* tag is rendered to create an error message. If the
+rendered text contains any HTML markup, then Zope will display
+the text as an error message on the browser, otherwise a generic
+error message is displayed.
+
+Here is a *raise* tag example::
+
+  <dtml-if expr="balance >= debit_amount">
+
+    <dtml-call expr="debitAccount(account, debit_amount)">
+
+    <p><dtml-var debit_amount> has been deducted from your
+    account <dtml-var account>.</p>
+
+  <dtml-else>
+
+    <dtml-raise type="Insufficient funds">
+
+      <p>There is not enough money in account <dtml-account> 
+      to cover the requested debit amount.</p>
+
+    </dtml-raise>
+
+  </dtml-if>
+
+There is an important side effect to raising an exception,
+exceptions cause the current transaction to be rolled back. This
+means any changes made by a web request are ignored. So in
+addition to reporting errors, exceptions allow you to back out
+changes if a problem crops up.
+
+The *Try* Tag
+~~~~~~~~~~~~~
+
+If an exception is raised either manually with the *raise* tag, or
+as the result of some error that Zope encounters, you can catch
+it with the *try* tag.
+
+Exceptions are unexpected errors that Zope encounters during the
+execution of a DTML document or method. Once an exception is
+detected, the normal execution of the DTML stops. Consider the
+following example::
+
+  Cost per unit: <dtml-var
+                       expr="_.float(total_cost/total_units)" 
+                       fmt=dollars-and-cents>
+
+This DTML works fine if *total_units* is not zero. However, if
+*total_units* is zero, a *ZeroDivisionError* exception is raised
+indicating an illegal operation. So rather than rendering the
+DTML, an error message will be returned.
+
+You can use the *try* tag to handle these kind of problems. With
+the *try* tag you can anticipate and handle errors yourself,
+rather than getting a Zope error message whenever an exception
+occurs.
+
+The *try* tag has two functions. First, if an exception is raised,
+the *try* tag gains control of execution and handles the exception
+appropriately, and thus avoids returning a Zope error
+message. Second, the *try* tag allows the rendering of any
+subsequent DTML to continue.
+
+Within the *try* tag are one or more *except* tags that identify and
+handle different exceptions. When an exception is raised, each
+*except* tag is checked in turn to see if it matches the
+exception's type. The first *except* tag to match handles the
+exception. If no exceptions are given in an *except* tag, then the
+*except* tag will match all exceptions.
+
+Here's how to use the *try* tag to avoid errors that could occur
+in the last example::
+
+  <dtml-try>
+
+    Cost per unit: <dtml-var 
+                         expr="_.float(total_cost/total_units)"
+                         fmt="dollars-and-cents">
+
+  <dtml-except ZeroDivisionError> 
+
+    Cost per unit: N/A 
+
+  </dtml-try> 
+
+If a *ZeroDivisionError* is raised, control goes to the *except*
+tag, and "Cost per unit: N/A" is rendered. Once the except tag
+block finishes, execution of DTML continues after the *try* block.
+
+DTML's *except* tags work with Python's class-based
+exceptions. In addition to matching exceptions by name, the
+except tag will match any subclass of the named exception. For
+example, if *ArithmeticError* is named in a *except* tag, the
+tag can handle all *ArithmeticError* subclasses including,
+*ZeroDivisionError*. See a Python reference such as the online
+`Python Library Reference
+<http://www.python.org/doc/current/lib/module-exceptions.html>`_
+for a list of Python exceptions and their subclasses.  An
+*except* tag can catch multiple exceptions by listing them all
+in the same tag.
+
+Inside the body of an *except* tag you can access information
+about the handled exception through several special
+variables.
+
+*error_type*
+    The type of the handled exception. 
+
+*error_value*
+    The value of the handled exception.
+
+*error_tb*
+    The traceback of the handled exception.
+
+You can use these variables to provide error messages to users
+or to take different actions such as sending email to the
+webmaster or logging errors depending on the type of error.
+
+The *Try* Tag Optional *Else* Block
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+The *try* tag has an optional *else* block that is rendered if an
+exception didn't occur.  Here's an example of how to use the
+*else* tag within the try tag::
+
+  <dtml-try> 
+
+    <dtml-call feedAlligators>
+
+  <dtml-except NotEnoughFood WrongKindOfFood>
+
+    <p>Make sure you have enough alligator food first.</p>
+
+  <dtml-except NotHungry> 
+
+    <p>The alligators aren't hungry yet.</p>
+
+  <dtml-except> 
+
+    <p>There was some problem trying to feed the alligators.<p>
+    <p>Error type: <dtml-var error_type></p>
+    <p>Error value: <dtml-var error_value></p>
+
+  <dtml-else> 
+
+    <p>The alligator were successfully fed.</p>
+
+  </dtml-try> 
+
+The first *except* block to match the type of error raised is
+rendered. If an *except* block has no name, then it matches all
+raised errors. The optional *else* block is rendered when no
+exception occurs in the *try* block. Exceptions in the *else*
+block are not handled by the preceding *except* blocks.
+
+The *Try* Tag Optional *Finally* Block
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+You can also use the *try* tag in a slightly different
+way. Instead of handling exceptions, the *try* tag can be used
+not to trap exceptions, but to clean up after them.
+
+The *finally* tag inside the *try* tag specifies a cleanup block
+to be rendered even when an exception occurs.
+
+The *finally* block is only useful if you need to clean up
+something that will not be cleaned up by the transaction abort
+code. The *finally* block will always be called, whether there
+is an exception or not and whether a *return* tag is used or
+not. If you use a *return* tag in the try block, any output of
+the *finally* block is discarded. Here's an example of how you
+might use the *finally* tag::
+
+  <dtml-call acquireLock>  
+  <dtml-try>
+      <dtml-call useLockedResource>
+  <dtml-finally>
+      <!-- this always gets done even if an exception is raised -->
+      <dtml-call releaseLock>
+  </dtml-try>
+
+In this example you first acquire a lock on a resource, then
+try to perform some action on the locked resource. If an
+exception is raised, you don't handle it, but you make sure to
+release the lock before passing control off to an exception
+handler. If all goes well and no exception is raised, you
+still release the lock at the end of the *try* block by
+executing the *finally* block.
+
+The *try/finally* form of the *try* tag is seldom used in
+Zope. This kind of complex programming control is often better
+done in Python or Perl.
+
+Other useful examples
+---------------------
+
+In this section are several useful examples of dtml code.  While
+many of these are most often better done in Python scripts, there
+are occasions when knowing how to accomplish this in dtml is
+worthwhile.
+
+Forwarding a REQUEST
+~~~~~~~~~~~~~~~~~~~~
+
+We have seen how to redirect the user's browser to another page
+with the help of the *call* directive.  However, there are times
+when a redirection is not necessary and a simple forwarding of a
+REQUEST from one dtml-method to another would suffice.  In this
+example, the dtml-method shown obtains a variable named *type*
+from the REQUEST object.  A lookup table is reference to obtain
+the name of the dtml-method to which the REQUEST should be
+forwarded.  The code below accomplishes this::
+
+  <dtml-let lookup="{'a' : 'form15', 'b' : 'form75', 'c' : 'form88'}">
+        <dtml-return "_[lookup[REQUEST.get('type')]]">
+  </dtml-let>
+
+This code looks up the name of the desired dtml-method in the
+lookup table (contained in the *let* statement) and in turn,
+looks up the name of this dtml-method in the current namespace.
+As long as the dtml-method exists, control will be passed to the
+method directly.  This example could be made more complete with
+the addition of exception handling which was discussed above.
+
+Sorting with the '<dtml-in>' tag
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are many times when sorting a result set is necessary.
+The *dtml-in* tag has some very interesting sort capabilities
+for both static and dynamic sorting.  In the example below, a
+ZSQL method is called that returns results from a log table.
+The columns returned are logTime, logType, and userName.  The
+dtml-method or document that contains this code will generate
+links back to itself to re-sort the query based upon certain
+search criteria::
+
+  <dtml-comment>
+
+  The sorting is accomplished by looking up a sort type
+  variable in the REQUEST that is comprised of two parts.  All
+  but the last character indicate the name of the column on
+  which to sort.  The last character of the sort type indicates
+  whether the sort should be ascending or descending.
+
+  </dtml-comment>
+
+  <table>
+    <tr>
+      <td>Time&nbsp;<a href="<dtml-var URL>?st=logTimea">A</a>&nbsp;<a href="<dtml-var URL>?st=logTimed">D</a></td>
+      <td>Type&nbsp;<a href="<dtml-var URL>?st=logTypea">A</a>&nbsp;<a href="<dtml-var URL>?st=logTyped">D</a></td>
+      <td>User&nbsp;<a href="<dtml-var URL>?st=userNamea">A</a>&nbsp;<a href="<dtml-var URL>?st=userNamed">D</a></td>
+    </tr>
+
+    <dtml-comment>The line below sets the default sort</dtml-comment>
+    <dtml-if "REQUEST.get('st')==None"><dtml-call "REQUEST.set('st', 'logTimed')"></dtml-if>
+    <dtml-in getLogData sort_expr="REQUEST.get('st')[0:-1]" reverse_expr="REQUEST.get('st')[-1]=='d'">
+      <tr>
+        <td><dtml-var logTime></td>
+        <td><dtml-var logType></td>
+        <td><dtml-var userName></td>
+      </tr>
+    </dtml-in>
+  </table>
+
+Calling a DTML object from a Python Script
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Although calling a DTML method from a Python script isn't really
+an advanced DTML technique, it deals with DTML, so it's being
+included here.  To call a DTML Method or DTML Document from a
+Python script, the following code is used::
+
+  dtmlMethodName = 'index_html'
+  return context[dtmlMethodName](container, container.REQUEST)
+
+It's as simple as that.  Often this is very useful if you wish
+to forward a request and significant processing is needed to
+determine which dtml object is the target.
+
+Explicit Lookups
+~~~~~~~~~~~~~~~~
+
+Occasionally it is useful to "turn off" acquisition when looking
+up an attribute.  In this example, you have a folder which
+contains sub-folders.  Each sub-folder contains Images.  The
+top-level folder, each subfolder, and each image contain a
+property named *desc*.
+
+If you were to query the Image for its *desc* property it would
+return the *desc* property of it's parent folder if the Image
+did not have the property.  This could cause confusion as the
+Image would appear to have the *desc* property when it really
+belonged to the parent folder.  In most cases, this behavior is
+desired.  However, in this case, the user would like to see
+which images have the *desc* property and which don't.  This is
+accomplished by utilizing *aq_explicit* in the call to the
+object in question.
+
+Given the following structure::
+
+ Folder 
+   |
+   |- Folder1 (desc='Folder one')
+   |- Folder2 (desc='Folder two')
+        |- Image1 (desc='Photo one')
+        |- Image2 
+        |- Image3 (desc='Photo three')
+
+when the second image is asked for its *desc* property it will
+return 'Folder two' based on acquisition rules::
+
+  <dtml-var "Image2.desc">
+
+However, utilizing *aq_explicit* will cause Zope to look only
+in the desired location for the property::
+
+  <dtml-var "Image2.aq_explicit.desc">
+
+This will, of course, raise an exception when the *desc*
+property does not exist.  A safer way to do this is::
+
+  <dtml-if "_.hasattr(Image2.aq_explicit, 'desc')">
+    <dtml-var "Image2.aq_explicit.desc">
+  <dtml-else>
+    No desc property.
+  </dtml-if>
+
+As you can see, this can be very useful.
+
+Conclusion
+----------
+
+DTML provides some very powerful functionality for designing web
+applications.  In this chapter, we looked at the more advanced
+DTML tags and some of their options.  A more complete reference
+can be found in Appendix A.
+
+The next chapter teaches you how to become a Page Template
+wizard. While DTML is a powerful tool, Page Templates provide a
+more elegant solution to HTML generation.

Copied: zope2book/trunk/source/DTML.rst (from rev 96594, zope2book/trunk/old/DTML.rst)
===================================================================
--- zope2book/trunk/source/DTML.rst	                        (rev 0)
+++ zope2book/trunk/source/DTML.rst	2009-02-16 18:00:15 UTC (rev 96595)
@@ -0,0 +1,1448 @@
+Basic DTML
+==========
+
+DTML (Document Template Markup Language) is a templating facility
+which supports the creation of dynamic HTML and text.  It is
+typically used in Zope to create dynamic web pages.  For example,
+you might use DTML to create a web page which "fills in" rows and
+cells of an HTML table contained within the page from data fetched
+out of a database.
+
+DTML is a *tag-based* presentation and scripting language.  This
+means that *tags* (e.g. '<dtml-var name>') embedded in your HTML
+cause parts of your page to be replaced with "computed" content.
+
+DTML is a "server-side" scripting language.  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.
+
+How DTML Relates to Similar Languages and Templating Facilities
+---------------------------------------------------------------
+
+DTML is similar in function to "HTML-embedded" scripting languages
+such as JSP, PHP, or mod_perl.  It differs from these facilities
+inasmuch as it will not allow you to create "inline" Python
+*statements* (if... then.. else..)  in the way that JSP, mod_perl
+or PHP will allow you to embed a block of their respective
+language's code into an HTML page. DTML does allow you to embed
+Python *expressions* (a == 1) into HTML-like tags.  It provides
+flow control and conditional logic by way of "special" HTML tags.
+It is more similar to Perl's 'HTML::Template' package than it is
+to mod_perl in this way.  It can also be compared to the web
+server facility of Server Side Includes (SSI), but with far more
+features and flexibility.
+
+When To Use DTML
+----------------
+
+If you want to make a set of dynamic web pages that share bits of
+content with each other, and you aren't working on a project that
+calls for a tremendous amount of collaboration between programmers
+and tool-wielding designers, DTML works well.  Likewise, if you
+want to dynamically create non-HTML text (like CSS stylesheets or
+email messages), DTML can help.
+
+When Not To Use DTML
+--------------------
+
+If you want code which expresses a set of complex algorithms to be
+maintainable (as "logic" programming should be), you shouldn't
+write it in DTML.  DTML is not a general purpose programming
+language, it instead is a special language designed for formatting
+and displaying content.  While it may be possible to implement
+complex algorithms in DTML, it is often painful.
+
+For example, let's suppose you want to write a web page which
+displays a representation of the famous `Fibonacci sequence
+<http://www.mathacademy.com/pr/prime/articles/fibonac/index.asp>`_.
+You would not want to write the program that actually makes the
+calculation of the Fibonacci numbers by writing DTML.  It could be
+done in DTML, but the result would be difficult to understand and
+maintain.  However, DTML is perfect for describing the page that
+the results of the Fibonnacci calculations are inserted into.  You
+can "call out" from DTML to Script (Python) objects as necessary
+and process the results of the call in DTML.  For example, it is
+`trivial in Python <http://www.python.org/doc/current/tut/node6.html>`_
+(search for the word Fibonacci on this page) to implement a Fibonacci
+sequence generator, and trivial in DTML to create a dynamic web
+page which shows these numbers in a readable format.  If you find
+yourself creating complex and hard-to-understand logic in DTML,
+it's likely time to explore the the Zope features which allow you
+to script "logic" in Python, while letting DTML do the
+presentation "dirty work".
+
+String processing is another area where DTML is likely not the
+best choice.  If you want to manipulate input from a user in a
+complex way, by using functions that manipulate strings, you are
+better off doing it in Python, which has more powerful string
+processing capabilities than DTML.
+
+Zope has a technology named `Zope Page emplates <ZPT.html>`_
+which has purpose similar to DTML.  DTML and ZPT are both
+facilities which allow you to create dynamic HTML.  However, DTML
+is capable of creating dynamic text which is *not* HTML, while ZPT
+is limited to creating text which is HTML (or XML).  DTML also
+allows users to embed more extensive "logic" in the form of
+conditionals and flow-control than does ZPT.  While the source to
+a ZPT page is almost always "well-formed" HTML through its
+lifetime, the source to DTML pages are not guaranteed to be
+"well-formed" HTML, and thus don't play well in many cases with
+external editing tools such as Dreamweaver.
+
+Both ZPT and DTML are fully supported technologies in Zope, and
+neither is "going away" any time soon.  A discussion about when to
+use one instead of the other is available in the chapter entitled
+`Using Basic Zope Objects <BasicObject.html>`_ in the section entitled
+"ZPT vs. DTML: Same Purpose, Different Audiences", but the choice
+is sometimes subjective.
+
+The Difference Between DTML Documents and DTML Methods
+------------------------------------------------------
+
+You can use DTML scripting commands in two types of Zope objects,
+*DTML Documents* and *DTML Methods*.  These two types of DTML
+objects are subtly different from one another, and their
+differences cause many would-be DTML programmers to become
+confused when deciding to use one versus the other.  So what is
+the difference?
+
+DTML Methods are used to carry out actions. They are
+*presentation* objects (as used in the vernacular of the `Using
+Basic Zope Objects`_ chapter).  If you want to
+render the properties or attributes of another object like a DTML
+Document or a Folder, you will use a DTML Method.  DTML Methods do
+not have their own properties.
+
+DTML Documents are *content* objects (in the vernacular used in
+the chapter entitled `Using Basic Zope Objects`_).
+If you want to create a "stand-alone" HTML or text document, you
+might create a DTML Document object to hold the HTML or text.
+DTML Document objects have their own *properties* (attributes),
+unlike DTML Methods.
+
+In almost all cases, you will want to use a DTML Method object to
+perform DTML scripting.  DTML Document objects are an artifact of
+Zope's history that is somewhat unfortunate.  In Zope's earlier
+days, a consensus came about that it was important to have objects
+in Zope that could perform DTML commands but have properties of
+their own.  At the time, the other content objects in Zope, such
+as Files and Images were either nonexistent or had limitations in
+functionality that made the concept of a DTML Document attractive.
+That attraction has waned as Zope's other built-in content objects
+have become more functional.  DTML Documents remain in Zope almost
+solely as a backwards-compatibility measure.  If you never use a
+DTML Document in your work with Zope, you won't miss out on
+much!
+
+Details
+-------
+
+DTML Methods are method objects.  The chapter named `Object
+Orientation <ObjectOrientation.html>`_ discusses the concept of a
+"method".  DTML Methods are *methods* of the folder that
+contains them, and thus they do not have regard for their own
+identity as a Zope object when they are used. For example, if
+you had a folder called Folder and a DTML method in that folder
+called Method::
+
+  AFolder/
+          AMethod
+
+AMethod is a *method* of AFolder. This means that AMethod does not
+have any of it's own attributes or properties.  Instead it uses
+those of AFolder. Suppose you put the following DTML string in
+AMethod::
+
+  <dtml-var id>
+
+When you view the AMethod DTML Method, you will see the string
+'AFolder', which is the 'id' of AMethod's containing Folder
+(AFolder). When this DTML method is viewed, it resolves the name
+'id' to the string which is the value of AFolder's 'id' property.
+
+DTML Documents, on the other hand, are not methods.  They are
+"aware" of their own identity as Zope objects. For example, if
+you created a DTML Document in the folder AFolder called
+ADocument, and you put the above DTML string into ADocument and
+viewed it, it would render to the string 'ADocument'.  It
+resolves the name 'id' to the string which is the value of
+its *own* id, not the id of its containing folder.
+
+.. important::
+   
+   For this chapter, unless stated otherwise, use DTML Methods to
+   hold the example DTML text, as opposed to DTML Documents!**
+
+DTML Tag Syntax
+---------------
+
+DTML contains two kinds of tags, *singleton* and *block* tags.
+Singleton tags consist of one tag enclosed by less-than (&lt;) and
+greater-than (&gt;) symbols.  The *var* tag is an example of a
+singleton tag::
+
+  <dtml-var parrot>
+
+There's no need to close the *var* tag with a '</dtml-var>' tag
+because it is a singleton tag.
+
+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.
+
+DTML Tag Names, Targets, and Attributes
+---------------------------------------
+
+All DTML tags have *names*.  The name is simply the word which
+follows 'dtml-'.  For instance, the name of the DTML tag
+'dtml-var' is 'var', and the name of the DTML tag 'dtml-in' is
+'in'.
+
+Most DTML tags have *targets*.  The target of a DTML tag is just
+the word or expression that, after a space, follows the tag
+name.  For example, the target of the DTML tag '<dtml-var
+standard_html_header>' is 'standard_html_header'.  The target of
+the DTML tag '<dtml-in foo>' is 'foo'.  The target of the DTML
+tag '<dtml-var "objectIds()"> is the expression "objectIds()".
+The target typically refers to the name of an object (or a
+Python expression that resolves to an object) that you wish the
+tag to operate upon.
+
+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 its target. 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>
+
+Here we are referencing the *exclamation* target, modifying it
+with the attribute *upper*.  Notice that the *upper* attribute,
+unlike the *missing* attribute doesn't need a value.
+
+See the `DTML Reference <AppendixA.html>`_ appendix for more
+information on the syntax of different DTML tags.
+
+Creating a "Sandbox" for the Examples in This Chapter
+-----------------------------------------------------
+
+You should create a Folder in your Zope's root folder named
+"DTML_Examples" if you intend on creating objects from examples in
+this chapter.  Create the example objects within this "sandbox".
+This prevents you from littering your Zope root folder with DTML
+examples.
+
+Examples of Using DTML for Common Tasks
+---------------------------------------
+
+Below, we show how to use DTML to complete three common tasks:
+inserting text into a web page, displaying results by iterating
+over a sequence, and processing form results.
+
+Inserting Text into HTML with DTML
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+DTML commands are written as tags that begin with *dtml-*.  You
+create dynamic content in DTML by mixing HTML tags and DTML tags
+together.  Inserting the value of a variable (a variable is also
+known as a "target") into HTML is the most basic task that you can
+perform with DTML.  Many DTML tags insert variable values, and
+they all do it in a similar way.  Let's look more closely at how
+Zope inserts variable values.
+
+Create a folder in your sandbox with the id "Feedbags" and the
+title "Bob's Fancy Feedbags". While inside the 'Feedbags' folder,
+create a DTML Method with an id of "pricelist". Note: an
+'id' is how you refer to an object such as a DTML Method
+or a Folder later on; titles are for informational
+purposes only. 
+
+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>
+
+Now view the DTML Method by clicking the *View* tab. When you view
+the DTML method this way, it will be *rendered*, which means that
+you will not necessarily see a straight representation of the HTML
+that you typed in to the form.  Instead you will see the
+*rendered* version of the page, which will include the extra text
+provided by DTML by way of the tags you've inserted.  You should
+see something like the figure below:
+
+.. figure:: ../Figures/9-1_bobsfeedbags.png
+
+   Viewing the pricelist method
+
+If you tell your browser to view the HTML source of the Workspace
+frame, you will see something not unlike the below::
+
+  <html>
+    <head><title>Bob's Fancy Feedbags</title>
+    </head>
+    <body bgcolor="#FFFFFF">
+      <h1>Price list for Bob's Fancy Feedbags</h1>
+      <p>Hemp Bag $2.50</p>
+      <p>Silk Bag $5.00</p>
+    </body>
+
+  </html>
+
+That's certainly not what you typed in, is it?
+
+DTML makes the reuse of content and layout possible.  In the
+example above, we've made use of the 'standard_html_header' DTML
+Method and the 'standard_html_footer' DTML Method, both of which
+live in the root folder, to insert HTML text into our page.  These
+DTML methods (and any other DTML method) can be used by other DTML
+methods to insert text into our rendered output.
+
+We've seen that DTML inserts an HTML header, an HTML footer, and a
+title into the web page.  But how does the "var" tag *find* the
+values that it inserts in place of "standard_html_header", "title"
+and "standard_html_footer"?
+
+DTML name lookup is somewhat "magical", because you don't need to
+explicitly tell DTML *where* to find a variable.  Instead, it
+tries to guess what you mean by following a preordained set of
+search rules.  DTML gets the values for variable names by
+searching an environment which includes the current object, the
+containment path, and request variables like values submitted by a
+form and cookies.  The `DTML Name Lookup Rules <AppendixE.html>`_
+represent the namespaces searched and their relative precedence.
+As an example, let's follow the 'pricelist' DTML code
+step-by-step.  In our 'pricelist' method, we've asked DTML to look
+up three names: "standard_html_header", "title", and
+"standard_html_footer".  It searches for these variables in the
+order that they are mentioned in the page.
+
+DTML looks first for "standard_html_header".  It looks in the
+"current object" first, which is its container, the 'Feedbags'
+folder. The 'Feedbags' folder doesn't have any methods or
+properties or sub-objects by that name. Next Zope tries to
+`acquire <Acquisition.html>`_ the object from its containers.  It
+examines the 'Feedbags' folder's container (your sandbox folder,
+likely named "DTML_Examples"), which also doesn't turn up
+anything.  It continues searching through any intermediate
+containters, which also don't have a method or property named
+"standard_html_header" unless you've put one there.  It keeps
+going until it gets to the root folder.  The root folder *does*
+have a sub-object named "standard_html_header", which comes as a
+default object in every Zope. The 'standard_html_header' object is
+a DTML Method. So Zope *calls* the 'standard_html_header' method
+in the root folder and inserts the results into the page.  Note
+that once DTML *finds* a property or variable, if it is callable
+(as in the case of a DTML Method, an External Method, a SQL
+Method, or a Script (Python) object), it is called and the results
+of the call are inserted into the page.
+
+Next DTML looks for the name "title". Here, the search is 
+shorter.  On its first try, DTML finds the 'Feedbags' folder's
+'title' property and inserts it.  The 'title' property is not a
+method or a script, so DTML doesn't need to *call* it.  It just
+renders it into the output.
+
+Finally DTML looks for the name *standard_html_footer*. It has to
+search all the way up to the root folder to find it, just like it
+looked for *standard_html_header*.  It calls the
+*standard_html_footer* in the root and inserts the text result.
+
+The resulting page is fully assembled (rendered) at this point,
+and is sent to your browser.
+
+Understanding how DTML looks up variables is important.  We will
+explore the DTML name lookup mechanism further in the chapter
+entitled `Variables and Advanced DTML <AdvDTML.html>`_.
+It is also documented in `Appendix E <AppendixE.html>`_.
+
+Formatting and Displaying Sequences
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is common that people want to use DTML to format and display
+*sequences*.  A sequence is just a list of items, like "Fred, Joe,
+Jim".  Often, you want to create an HTML table or a bulleted list
+that contains elements in a sequence.  Let's use DTML to call out
+to an object which returns a sequence and render its result.
+
+Create a Script (Python) object named "actors" in your
+sandbox folder. Give the script the following body and
+save it::
+
+  ## Script (Python) "actors"
+  ##bind container=container
+  ##bind context=context
+  ##bind namespace=
+  ##bind script=script
+  ##bind subpath=traverse_subpath
+  ##parameters=
+  ##title=
+  ##
+  return ['Jack Lemmon', 'Ed Harris','Al Pacino', 'Kevin Spacey', 'Alan Arkin']
+
+Make sure that all of the lines of this script line up along the
+left-hand side of the textarea to avoid receiving an error when
+you attempt to save the script, since Python is sensitive to
+indentation.  Don't worry about the '##'s for now, we will
+explain these later.  
+
+This Script (Python) object returns a Python data
+structure which is a *list* of *strings*.  A list is a kind of
+*sequence*, which means that DTML can *iterate* over it using the
+*dtml-in* tag.  Now create a DTML Method named "showActors" in
+your sandbox, give it this body, and save it::
+
+  <html>
+  <body>
+  <h1>Actors in the movie Glengarry Glen Ross</h1>
+  <table border="1">
+    <th>Name</th>
+  <dtml-in actors>
+    <tr>
+    <td><dtml-var sequence-item></td>
+    </tr>
+  </dtml-in>
+  </table>
+  </body>
+  </html>
+
+The DTML *in* tag iterates over the results of the *actors* script
+and inserts a table row into a table for each of the actors
+mentioned in the script.  Note that inside the table cell, we use
+a special name *sequence-item*.  *sequence-item* is a special name
+that is meaningful within a *dtml-in* tag.  It refers to the
+"current item" (in this case, the actor name string) during
+processing.  The HTML source of the Workspace frame when you click
+the *View* tab on the 'showActors' method will look something
+like::
+
+  <html>
+  <body>
+  <h1>Actors in the movie Glengarry Glen Ross</h1>
+  <table border="1">
+    <th>Name</th>
+          <tr>
+    <td>Jack Lemmon</td>
+
+    </tr>
+          <tr>
+    <td>Ed Harris</td>
+    </tr>
+          <tr>
+    <td>Al Pacino</td>
+    </tr>
+          <tr>
+
+    <td>Kevin Spacey</td>
+    </tr>
+          <tr>
+    <td>Alan Arkin</td>
+    </tr>
+        </table>
+  </body>
+  </html>
+
+Note that you didn't have to specifically tell DTML that you are
+querying a Script (Python) object.  You just tell it the name of
+the object to call (in this case 'actors'), and it does the work
+of figuring out how to call the object and pass it appropriate
+arguments. If you replace the 'actors' Script with some other kind
+of object that does exactly the same thing, like another DTML
+Method, you won't have to change your 'showActors' DTML Method.
+It will "just work".
+
+Processing Input from Forms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can use DTML to perform actions based on the information
+contained in the submission of an HTML form.
+
+Create a DTML Method named "infoForm" with the following body::
+
+  <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_addr"><br>
+  <input type="submit" name="submit" value=" Submit ">
+  </form>
+
+  <dtml-var standard_html_footer>
+
+This is a web form that asks the user for information,
+specifically his user name and email address.  Note that you refer
+to the name "infoAction" as the *action* of the HTML form.  This
+really has nothing to do with DTML, it's an attribute of the HTML
+*form* tag.  But the name specified in the form action tag can
+name another Zope object which will receive and process the
+results of the form when it is submitted.
+
+Create a DTML Method named *infoAction* in the same folder as the
+'infoForm' method.  This is the *target* of the 'infoForm' form
+action.  This method will display a bland "thanks" message which
+includes the name and email information that was gathered from the
+web form.  Provide the *infoAction* method with the following body
+and save it::
+
+  <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_addr> describing our aardvark adoption
+  program as soon as it receives final governmental approval.
+  </p>
+
+  <dtml-var standard_html_footer>
+
+Navigate back to the 'infoForm' method and use the *View* tab to
+execute it.  Fill out the form and click the *Submit* button. If
+all goes well you should see a thank you message that includes
+your name and email address, much like the figure below:
+
+.. figure:: ../Figures/aardvarkview.png
+
+   Result of submitting the infoForm method
+
+The Zope object named *REQUEST* contains information about the
+current web request.  This object is in the DTML name lookup path.
+The 'infoAction' method found the form information from the web
+request that happened when you clicked the submit button on the
+rendering of 'infoForm'.  DTML looks for variables in the current
+web request, so you can just refer to the form variable names in
+the target method by name.  In our case, we were able to display
+the values of the form elements *user_name* and *email_addr* in
+the 'infoAction' method just by referring to them by name in their
+respective *dtml-var* tags.  DTML used its `lookup
+rules <AppendixE.html>`_ to search for the variable names.  It found
+the names in the "REQUEST.form" namespace and displayed them.  If
+it had found an object with either name *email_addr* or
+*user_name* earlier in the lookup (if perhaps there was a Zope
+object in your acquisition path named 'user_name') it would have
+found this object first and rendered its results.  But, mostly by
+chance, it didn't, and found the name in REQUEST instead.
+
+Let's examine the contents of the Zope REQUEST object in order to
+shed more light on the situation.  Create a new DTML Method object
+named 'show_request' in your sandbox folder.  Give it the the
+following body::
+
+  <dtml-var REQUEST>
+
+The 'show_request' method will render a human-readable
+representation of Zope's REQUEST object when you click submit on
+the 'infoForm' rendering.  Visit the 'infoForm' method, and change
+it to the following::
+
+  <dtml-var standard_html_header>
+
+  <p>Please send me information on your aardvark adoption
+  program.</p>
+
+  <form action="show_request">
+  name: <input type="text" name="user_name"><br>
+  email: <input type="text" name="email_addr"><br>
+  <input type="submit" name="submit" value=" Submit ">
+  </form>
+
+  <dtml-var standard_html_footer>
+
+We changed the form action of the 'infoForm' method to
+*show_request*.  Now click the *View* tab of the new 'infoForm'
+method.  Fill in some information in the form elements, and click
+*Submit*.  You will see something like the following::
+
+  form
+   submit ' Submit '
+   email_addr 'chrism at zope.com'
+   user_name 'Chris'
+
+  cookies
+   tree-s 'eJzTiFZ3hANPW/VYHU0ALlYElA'
+
+  lazy items
+   SESSION <bound method SessionDataManager.getSessionData of <SessionDataManager instance at 897d020>
+
+  other
+   AUTHENTICATION_PATH ''
+   user_name 'Chris'
+   PUBLISHED <DTMLMethod instance at 8a62670>
+   submit ' Submit '
+   SERVER_URL 'http://localsaints:8084'
+   email_addr 'chrism at zope.com'
+   tree-s 'eJzTiFZ3hANPW/VYHU0ALlYElA'
+   URL 'http://localsaints:8084/DTML_Example/show_request'
+   AUTHENTICATED_USER admin
+   TraversalRequestNameStack []
+   URL0 http://localsaints:8084/DTML_Example/show_request
+   URL1 http://localsaints:8084/DTML_Example
+   URL2 http://localsaints:8084
+   BASE0 http://localsaints:8084
+   BASE1 http://localsaints:8084
+   BASE2 http://localsaints:8084/DTML_Example
+   BASE3 http://localsaints:8084/DTML_Example/show_request
+
+  environ
+   SCRIPT_NAME ''
+   HTTP_ACCEPT_ENCODING 'gzip, deflate, compress;q=0.9'
+   SERVER_PORT '8084'
+   PATH_TRANSLATED '/DTML_Example/show_request'
+   HTTP_ACCEPT 'text/xml...'
+   GATEWAY_INTERFACE 'CGI/1.1'
+   HTTP_COOKIE 'tree-s="eJzTiFZ3hANPW/VYHU0ALlYElA"'
+   HTTP_ACCEPT_LANGUAGE 'en-us, en;q=0.50'
+   REMOTE_ADDR '192.168.1.3'
+   SERVER_NAME 'saints'
+   HTTP_USER_AGENT 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1a+) Gecko/20020629'
+   HTTP_ACCEPT_CHARSET 'ISO-8859-1, utf-8;q=0.66, *;q=0.66'
+   CONNECTION_TYPE 'keep-alive'
+   channel.creation_time 1027876407
+   QUERY_STRING 'user_name=Chris&email_addr=chrism%40zope.com&submit=+Submit+'
+   SERVER_PROTOCOL 'HTTP/1.1'
+   HTTP_KEEP_ALIVE '300'
+   HTTP_HOST 'localsaints:8084'
+   REQUEST_METHOD 'GET'
+   PATH_INFO '/DTML_Example/show_request'
+   SERVER_SOFTWARE 'Zope/(unreleased version, python 2.1.3, linux2) ZServer/1.1b1'
+   HTTP_REFERER 'http://localsaints:8084/DTML_Example/infoForm'
+
+You have instructed the 'show_request' method to render the
+contents of the web request initiated by the 'infoForm' method.
+Note that each section (form, cookies, lazy items, other, and
+environ) represents a *namespace* inside the REQUEST.  DTML
+searches all of these namespaces for the names you refer to in
+your 'infoForm' form.  Note that *email_addr* and *user_name* are
+in the "form" namespace of the REQUEST.  There is lots of
+information in the rendering of the REQUEST, but for us, this is
+the most pertinent.  For more information on the REQUEST object,
+visit the Zope Help system, and choose Zope Help -> API Reference
+-> Request.
+
+Dealing With Errors
+~~~~~~~~~~~~~~~~~~~
+
+Let's perform an experiment. What happens if you try to view the
+'infoAction' method you created in the last section directly, as
+opposed to getting to it by submitting the 'infoForm' method?
+Click on the 'infoAction' method and then click the *View* tab.
+You will see results not unlike those in the figure below.
+
+.. figure:: ../Figures/infokeyerror.png
+
+   DTML error resulting from a failed variable lookup
+
+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.  You can examine the error by
+visiting the *error_log* object in your root folder.  In this
+case, we know why the error occurred, so visiting the error in the
+*error_log* isn't really necessary.  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>
+
+Understanding where DTML looks for variables will help you figure
+out how to fix this kind of problem.  In this case, you have
+viewed a method 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
+(its parent folders) 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.
+
+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 the 'standard_html_method' object or
+property is located. Zope will search upwards in the object
+database until it finds the 'standard_html_header' that is defined
+in the root folder.
+
+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 new folder in your "sandbox" folder with an id of
+"Green". Enter the 'Green' folder and create a DTML Method with an
+id of "welcome". Edit the 'welcome' DTML Method to have these
+contents::
+
+  <dtml-var standard_html_header>
+
+  <p>Welcome</p>
+
+  <dtml-var standard_html_footer>
+
+Now view the 'welcome' method. It should look like a simple web
+page with the word *welcome*, as shown in the figure below.
+
+.. figure:: ../Figures/welcomedtml.png
+
+   Welcome method
+
+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". Give it the following body::
+
+  <html>
+  <head>
+    <style type="text/css">
+    body {color: #00FF00;}
+    p {font-family: sans-serif;}
+    </style>
+  </head>
+  <body>
+
+Notice that this is not a complete web page. For example, it does
+not have an ending '</html>' tag.  This is just a fragment of HTML
+that will be used as a header, meant to be included into other
+pages. This header uses `CSS <http://www.w3.org/Style/CSS>`_
+(Cascading Style Sheets) to make some changes to the look and feel
+of web pages.
+
+Now revisit the 'welcome' method and click its *View* tab again.
+You will see something like the figure below:
+
+.. figure:: ../Figures/welcomegreen.png
+
+   Welcome method with custom header
+
+The rendering 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.
+
+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.  You can of course also create a
+'standard_html_footer', providing it with local content as well.
+
+Using this pattern you can quickly change the look and feel of
+different parts of your website. 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 object which represents the variable and
+calling it if necessary. We call this basic tag syntax *name*
+syntax to differentiate it from *expression* syntax.
+
+When you use DTML name syntax, DTML tries to do the right thing to
+insert the results of the object looked up by the variable name,
+no matter what that object may be. In general this means that if
+the variable is another DTML Method or DTML Document, it will be
+called with appropriate arguments.  However, if the variable is
+*not* another DTML Method or DTML Document, and it requires
+parameters, you need to explicitly pass the arguments along using
+an expression.
+
+*Expressions* used in DTML allow you to be more explicit about how
+to find and call variables. Expressions are tag attributes that
+contain small snippets of code in the Python programming language.
+These are typically referred to as *Python expressions*.
+
+A Python expression is essentially any bit of code that *is not* a
+Python *statement*.  For example, the Python statement 'a = 1'
+assigns "1" to the "a" variable. You cannot use this statement in
+DTML expressions.  Likewise, you cannot use the statement 'print
+"x"' in DTML.  It is not an expression.  Essentially, an
+expression must be a combination of values, variables, and Python
+*operators*.  To find out more about Python's expression syntax,
+see the `Python Tutorial <http://www.python.org/doc/current/tut>`_
+at the Python.org website.  For more information specifically about
+the differences between Python expressions and statements, see the
+`Variables, expressions, and statements
+<http://www.ibiblio.org/obp/thinkCSpy/chap02.htm>`_
+chapter of *How To Think Like a Computer Scientist Using Python*.
+
+An expression always results in a return value.  For example, the
+Python expression "a == 5" returns the integer 1 if "a" is equal
+to the integer 5 or the integer 0 if "a" is not equal to the
+integer 5.  The return value of an expression is used by DTML as
+the *target* of the DTML command.
+
+The primary difference in DTML between using *expressions* as
+targets and *names* as targets is that DTML does some magic after
+it locates a *named* targets that it does not do after it finds an
+expression targets.  For example, after finding object with the
+name 'standard_html_header' in the root folder via the name-syntax
+DTML command '<dtml-var standard_html_header>', DTML *calls* the
+'standard_html_header' object, inserting the results into the
+page.  However, when you use an expression-syntax DTML command,
+like '<dtml-var expr="standard_html_header">', DTML *will not*
+call the 'standard_html_header' object.  Instead it will return a
+representation of the object as a string.  In order to *call* the
+'standard_html_header' object in an expression-syntax DTML tag,
+you need to do it explicitly by passing along arguments.  When you
+delve into the realm of DTML expression syntax, DTML "magic" goes
+away, and you need to become aware of the arguments accepted by
+the target (if any) and pass them along.
+
+Let's create a Script (Python) object named 'getHippo' that *must*
+be called in DTML with expression syntax, because it takes a
+non-optional argument that *named* DTML syntax cannot provide.
+
+Create a Script (Python) in your sandbox folder named *getHippo*.
+Provide it with the following body::
+
+  ## Script (Python) "getHippo"
+  ##bind container=container
+  ##bind context=context
+  ##bind namespace=
+  ##bind script=script
+  ##bind subpath=traverse_subpath
+  ##parameters=trap
+  ##title=
+  ##
+  return 'The hippo was captured with a %s.' % trap
+
+Note that this Script (Python) object takes a single parameter
+named "trap".  It is not an optional parameter, so we need to pass
+a value in to this script for it to do anything useful.
+
+Now let's make a DTML method to call 'getHippo'.  Instead of
+letting DTML find and call *getHippo*, we can use an expression to
+explicitly pass arguments.  Create a DTML method named *showHippo*
+and give it the following body::
+
+  <dtml-var expr="getHippo('large net')">
+
+Here we've used a Python expression to explicitly call the
+'getHippo' method with the string argument, 'large net'.  View the
+'showHippo' DTML Method.  It will return a result not unlike the
+following::
+
+    The hippo was captured with a large net.
+
+To see why we need to use expression syntax to call this script,
+let's modify the 'showHippo' method to use DTML name syntax::
+
+  <dtml-var getHippo>
+
+View the method.  You will receive an error not unlike the
+following::
+
+  Error Type: TypeError
+  Error Value: getHippo() takes exactly 1 argument (0 given)
+
+The 'getHippo' method requires that you pass in an argument,
+'trap', that cannot be provided using DTML name syntax.  Thus, you
+receive an error when you try to view the 'showHippo' method.
+
+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>
+
+and::
+
+  <dtml-var expr="objectValues">
+
+These two examples if you are to put them in a DTML Method will
+end up giving you two completely different results. The first
+example of the DTML *var* tag will automatically *call* the
+object which is represented by *objectValues*. 
+
+In an expression, you have complete control over the variable
+rendering.  In the case of our example, *objectValues* is a
+method implemented in Python which returns the values of the
+objects in the current folder.  It has no required arguments.
+So::
+
+  <dtml-var objectValues>
+
+will call the method.
+However:
+
+  <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.
+
+To call a Python method which requires no arguments 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">
+
+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.
+
+Common DTML Tags
+----------------
+
+Below, we discuss the most common DTML tags: the *var* tag, the
+*if* tag, the *else* tag, the *elif* tag, and the *in* tag,
+providing examples for the usage of each.
+
+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.  Note that as of Zope 2.6, all string
+  values which are retrieved from the REQUEST namespace are HTML-quoted by
+  default.  This helps to prevent "cross-site scripting" security holes
+  present in earlier Zope versions, where a user could insert some clever
+  JavaScript into a page in order to possibly make you divulge information
+  to him which could be private.  For more information, see the `CERT
+  advisory <http://www.cert.org/advisories/CA-2000-02.html>`_ on the topic.
+
+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 <AppendixA.html>`_.
+
+  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 - Oct. 31, 2003 11:02 am:
+     I think this is the first mention of Properties.... Would be
+     helpful to explain that the properties are found with the
+     properties tag....since up until nos almost all additions have
+     been done by the pulldown menu.:)
+
+  You can display this cost in a DTML Document or Method like so::
+
+    One Adult pass: <dtml-var adult_rate fmt=dollars-and-cents>
+
+  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;
+
+This is equivalent to::
+
+  <dtml-var name="cockatiel" html_quote>
+
+Entity-syntax-based DTML tags always "html quote" their
+renderings.  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" html_quote>">
+
+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 within entity-based DTML syntax and many DTML
+attributes won't work with it. See `Appendix A`_
+for more information on *var* tag entity syntax.
+
+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.
+
+The *if* tag is a block tag. The block inside the *if* tag is executed
+if the condition is true.
+
+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 can 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>
+
+Nested *if* tags work by evaluating the first condition, and if that
+condition is true, then they evaluate the second
+condition.  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>  
+
+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>
+
+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.
+
+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.
+
+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>
+    <p>Zoo admission for first time visitors
+         <dtml-var expr="adult_rate/2" fmt="dollars-and-cents"></p>
+  </dtml-if>  
+
+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 that has no
+parameters.::
+
+  ## Script(Python) "hasVisitedZoo"
+  ##
+  """
+  Returns true if the user has previously visited
+  the Zoo. Uses cookies to keep track of zoo visits.
+  """
+  request = context.REQUEST
+  response = request.RESPONSE
+  if request.has_key('zooVisitCookie'):
+      return 1
+  else:
+      response.setCookie('zooVisitCookie', '1')
+      return 0
+
+In the chapter entitled `Advanced Zope Scripting <ScriptingZope.html>`_,
+we'll look more closely at how to script business logic with Python.  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 chapter entitled `Basic Zope Objects`_.
+Create a DTML Method with the following body::
+
+  <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>
+
+This code displayed the following file listing, as shown in the
+figure below.
+
+.. figure:: ../Figures/4-4.png
+
+   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 method.  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.
+
+During each iteration, the *in* tag looks for variables in the
+current object, first. In the chapter entitled `Variables and
+Advanced DTML`_ we'll look more closely at how DTML
+looks up variables.
+
+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.
+
+*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 the figure below.
+
+.. figure:: ../Figures/4-5.png
+
+   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>
+
+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 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.
+
+These special variables are detailed more thoroughly in `Appendix A`_.
+
+Summary
+-------
+
+DTML is a powerful tool for creating dynamic content. It allows you to
+perform fairly complex calculations. In the chapter entitled `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 the
+chapter entitled `Advanced Zope Scripting`_ you'll find out about how to
+use Python for scripting business logic.

Modified: zope2book/trunk/source/Preface.rst
===================================================================
--- zope2book/trunk/source/Preface.rst	2009-02-16 17:37:29 UTC (rev 96594)
+++ zope2book/trunk/source/Preface.rst	2009-02-16 18:00:15 UTC (rev 96595)
@@ -137,15 +137,28 @@
     don't readily fit into any of the basic "content,"
     "presentation," or "logic" object groups.
 
-14. Searching and Categorizing Content
+14. Basic DTML
 
+    This chapter introduces DTML, the second tag-based scripting language.
+    You'll learn DTML syntax, its basic tags, and how to use DTML templates
+    and scripting facilities. After reading this chapter, you'll be able to
+    create dynamic web pages with DTML.
+
+15. Advanced DTML
+
+    This chapter takes a closer look at DTML. You'll learn about DTML security,
+    the tricky issue of how variables are looked up in DTML, advanced use of
+    basic tags, and the myriad of special purpose tags.
+
+16. Searching and Categorizing Content
+
     This chapter shows you how to index and search objects with
     Zope's built-in search engine: the *Catalog*. You'll learn about 
     indexing concepts, different patterns for
     indexing and searching, metadata, and
     search results. 
 
-15. Relational Database Connectivity
+17. Relational Database Connectivity
 
     This chapter describes how Zope connects to external
     relational databases.  You'll learn about features that allow you
@@ -153,7 +166,7 @@
     objects, and security and performance
     considerations.
 
-16. Virtual Hosting Services
+18. Virtual Hosting Services
 
     This chapter explains how to set up Zope in a "virtual hosting"
     environment, in which Zope sub-folders can be served as "top-level"
@@ -161,12 +174,12 @@
     be performed either "natively" or using Apache's 'mod_rewrite'
     facility.
 
-17. Sessions
+19. Sessions
 
     This chapter describes Zope's "sessioning" services, which allow
     Zope developers to "keep state" between HTTP requests.
 
-18. Scalability and ZEO
+20. Scalability and ZEO
 
     This chapter covers issues and solutions for building and
     maintaining large web applications, and focuses on issues of
@@ -175,38 +188,38 @@
     tools and techniques needed to turn a small site into a
     large-scale site, servicing many simultaneous visitors.
 
-19. Managing Zope Objects Using External Tools
+21. Managing Zope Objects Using External Tools
 
     This chapter explains how to use tools outside of your web
     browser to manipulate Zope objects.
 
-20. Extending Zope
+22. Extending Zope
 
     This chapter covers extending Zope by creating your own classes of objects.
     You'll learn how to create Python base classes and about the base classes
     that ship with Zope.
 
-21. Maintaining Zope
+23. Maintaining Zope
 
     This chapter covers Zope maintenance and administration tasks,
     such as database "packing" and package installation.
 
-22. Appendix A: DTML Reference
+24. Appendix A: DTML Reference
 
     Reference of DTML syntax and commands.
 
-23. Appendix B:  API Reference
+25. Appendix B:  API Reference
 
     Reference of Zope object APIs.
 
-24. Appendix C:  Page Template Reference
+26. Appendix C:  Page Template Reference
 
     Reference of Zope Page Template syntax and commands.
 
-25. Appendix D:  Zope Resources
+27. Appendix D:  Zope Resources
 
     Reference of "resources" which can be used to further enhance
     your Zope learning experience.
 
-26. Appendix E: DTML Name Lookup Rules
+28. Appendix E: DTML Name Lookup Rules
     Describes DTML's name lookup rules.

Modified: zope2book/trunk/source/index.rst
===================================================================
--- zope2book/trunk/source/index.rst	2009-02-16 17:37:29 UTC (rev 96594)
+++ zope2book/trunk/source/index.rst	2009-02-16 18:00:15 UTC (rev 96595)
@@ -25,6 +25,8 @@
    AdvZPT.rst
    ScriptingZope.rst
    ZopeServices.rst
+   DTML.rst
+   AdvDTML.rst
    SearchingZCatalog.rst
    RelationalDatabases.rst
    VirtualHosting.rst



More information about the Checkins mailing list