Sophie

Sophie

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

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

<html>
<head>
<title>Chapter 8: Variables and Advanced DTML</title>
</head>
<body bgcolor="#FFFFFF">
<h1>Chapter 8: Variables and Advanced DTML</h1>
<p>  DTML is the kind of language that "does 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, it's bad.  This chapter tells you how to make DTML
  do what you <em>really</em> mean.</p><p>  It's no lie that DTML has reputation for complexity.  And it's true,
  DTML is really simple if you all you want to do is simple layout,
  like you've seen so far.  However, if you want to use DTML for more
  advanced tasks, you have to understand where DTML variables come
  from.</p><p>  Here's a very tricky error that almost all newbies encounter.
  Imagine you have a DTML Document named called <em>zooName</em>.  This
  document contains an HTML form like the following:<pre>    &lt;dtml-var standard_html_header&gt;

      &lt;dtml-if zooName&gt;

        &lt;p&gt;&lt;dtml-var zooName&gt;&lt;/p&gt;

      &lt;dtml-else&gt;

        &lt;form action=&quot;&lt;dtml-var URL&gt;&quot; method=&quot;GET&quot;&gt;
          &lt;input name=&quot;zooName&quot;&gt;
          &lt;input type=&quot;submit&quot; value=&quot;What is zooName?&quot;&gt;
        &lt;/form&gt;

      &lt;/dtml-if&gt;  

    &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>  This looks simple enough, the idea is, this is an HTML page that calls
  itself.  This is because the HTML action is the <em>URL</em> variable, which
  will become the URL of the DTML Document.  </p><p>  If there is a <code>zooName</code> 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 entered in the form.</p><p>  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 <em>zooName</em>, and it doesn't use the variable out of the
  request, it uses itself, which causes it 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 sections, we'll show you how to fix this
  example to do what you mean.</p><h2>  How Variables are Looked up</h2>
<p>    There's are actually two ways to fix the DTML error in the
    <em>zooName</em> document.  The first is that you can rename the document
    to something like <em>zopeNameFormOrReply</em> and always remember this
    special exception and never do it; never knowning 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
    <em>namespace</em>.</p><p>    The DTML namespace is a collection of objects arranged in a <em>stack</em>.  A
    stack is a list of objects that can manipulated by <em>pushing</em> and
    <em>popping</em> objects on to and off of the stack. </p><p>    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.</p><p>    When Zope looks for names in the DTML namespace stack it first looks at
    the very top most object in the stack.  If the name can't be found
    there, then the next item down is looked in.  Zope will work its way
    down the stack, checking each object in turn until it finds the name
    that it is looking for.</p><p>    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, <em>unicorn</em>:<pre>      &lt;dtml-var unicorn&gt;</pre>
</p><p>    As long as there is no variable named <em>unicorn</em> viewing this
    DTML will return an error, as shown in <a href="#7-1">Figure 7-1</a>.</p><p>    <a name="7-1"></a>
<img src="Figures/7-1.png" alt="DTML error message indicating that it cannot find a
    variable.">
<p><b>Figure 7-1</b> DTML error message indicating that it cannot find a
    variable.</p>
</p><p>    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.</p><h2>  DTML Namespaces</h2>
<p>    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 <a href="#7-2">Figure 7-2</a></p><p>    <a name="7-2"></a>
<img src="Figures/7-2.png" alt="Initial DTML namespace stack.">
<p><b>Figure 7-2</b> Initial DTML namespace stack.</p>
</p><p>    The client object is the first object on the top of the DTML namespace
    stack.  What the client object is depends on whether or not you are
    executing a DTML Method or a DTML Document.  In our example above, this
    means that the client object is named <em>zooName</em>.  Which is why it
    breaks.  The form input that we really wanted comes from the web
    request, but the client is looked at first.</p><p>    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 <code>with</code> tag:<pre>      &lt;dtml-var standard_html_header&gt;

        &lt;dtml-with REQUEST only&gt;
          &lt;dtml-if zooName&gt;
            &lt;p&gt;&lt;dtml-var zooName&gt;&lt;/p&gt;
          &lt;dtml-else&gt;
            &lt;form action=&quot;&lt;dtml-var URL&gt;&quot; method=&quot;GET&quot;&gt;
              &lt;input name=&quot;zooName&quot;&gt;
              &lt;input type=&quot;submit&quot; value=&quot;What is zooName?&quot;&gt;
            &lt;/form&gt;
          &lt;/dtml-if&gt;
        &lt;/dtml-with&gt;

      &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>    Here, the with tag says to look in the <code>REQUEST</code> namespace, and <em>only</em>
    the <code>REQUEST</code> namespace, for the name "zooName".</p><h3>    DTML Client Object  </h3>
<p>      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.</p><p>      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
      <em>list</em> in the root folder:<pre>        &lt;dtml-var standard_html_header&gt;

        &lt;ul&gt;
        &lt;dtml-in objectValues&gt;
          &lt;li&gt;&lt;dtml-var title_or_id&gt;&lt;/li&gt;
        &lt;/dtml-in&gt;
        &lt;/ul&gt;

        &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>      Now, what this method displays depends upon how it is used.  If
      you apply this method to the <em>Reptiles</em> folder with the URL
      <code>http://localhost:8080/Reptiles/list</code>, then you will get
      something that looks like <a href="#7-3">Figure 7-3</a>.</p><p>      <a name="7-3"></a>
<img src="Figures/7-3.png" alt="Applying the list method to the Reptiles
      folder.">
<p><b>Figure 7-3</b> Applying the list method to the Reptiles
      folder.</p>
</p><p>      But if you were to apply the method to the <em>Birds</em> folder with
      the URL <em>http://localhost:8080/Birds/list</em> then you would get
      something different, only two items in the list, <em>Parrot</em> and
      <em>Raptors</em>.</p><p>      Same DTML Method, different results. In the first example, the client
      object of the <em>list</em> method was the <em>Reptiles</em> folder.  In the second
      example, the client object was the <em>Birds</em> folder. When Zope looked
      up the <em>objectValues</em> variable, in the first case it called the
      <em>objectValues</em> method of the <em>Reptiles</em> folder, in the second case it
      called the <em>objectValues</em> method of the <em>Birds</em> folder.</p><p>      In other words, the client object is where variables such as
      methods, and properties are looked up first.</p><p>      As you saw in Chapter 4, "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.</p><h3>    DTML Request Object</h3>
<p>      The request object is the very bottom most object on the DTML
      namespace stack.  The request contains all of the information
      specific to the current web request.</p><p>      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:<ol>
<li> The CGI environment. The <a href="http://www.w3.org/CGI/">Common Gateway
           Interface</a>, 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.</li>
<li> 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.</li>
<li> Cookies. If the client of the current request has any cookies
           these can be found in the current REQUEST object.</li>
<li> 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.</li>
</ol>
</p><p>      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.</p><p>      A very simple and enlightening example is to simply print the REQUEST
      out in an HTML page:<pre>        &lt;dtml-var standard_html_header&gt;

        &lt;dtml-var REQUEST&gt;

        &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>      Try this yourself, you should get something that looks like
      <a href="#7-4">Figure 7-4</a>.</p><p>      <a name="7-4"></a>
<img src="Figures/7-4.png" alt="Displaying the request.">
<p><b>Figure 7-4</b> Displaying the request.</p>
</p><p>      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.</p><h3>    Rendering Variables</h3>
<p>      When you insert a variable using the <em>var</em> tag, Zope first looks
      up the variable using the DTML namespace, it then <em>renders</em> 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.</p><p>      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 <code>getitem</code> DTML utility function.</p><h2>  Modifying the DTML Namespace</h2>
<p>    Now that you have seen that the DTML namespace is a stack, you may
    be wondering how, or even why, new objects get pushed onto it.</p><p>    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 <em>in</em> tag, the <em>with</em>
    tag, and the <em>let</em> tag.</p><h3>    <em>In</em> Tag Namespace Modifications</h3>
<p>      When the <em>in</em> tag iterates over a sequence it pushes the current
      item in the sequence onto the top of the namespace stack:<pre>        &lt;dtml-var getId&gt; &lt;!-- This is the id of the client object --&gt;

        &lt;dtml-in objectValues&gt;

          &lt;dtml-var getId&gt; &lt;!-- this is the id of the current item in the 
                             objectValues sequence --&gt;
        &lt;/dtml-in&gt;</pre>
</p><p>      You've seen this many times throughout the examples in this
      book.  While the <em>in</em> 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.</p><h3>    The <em>With</em> Tag</h3>
<p>      The <em>with</em> tag pushes an object that you specify onto the top of
      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.</p><p>      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:<pre>        &lt;dtml-var standard_html_header&gt;

        &lt;dtml-var expr=&quot;Reptiles.getReptileInfo()&quot;&gt;
        &lt;dtml-var expr=&quot;Reptiles.reptileHouseMaintainer&quot;&gt;

        &lt;dtml-in expr=&quot;Reptiles.getReptiles()&quot;&gt;
          &lt;dtml-var species&gt;
        &lt;/dtml-in&gt;

        &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>      Notice that a lot of complexity is added to the code just to get
      things out of the <em>Reptiles</em> folder. Using the <em>with</em> tag you can
      make this example much easier to read:<pre>        &lt;dtml-var standard_html_header&gt;

        &lt;dtml-with Reptiles&gt;

          &lt;dtml-var getReptileInfo&gt;
          &lt;dtml-var reptileHouseMaintainer&gt;

          &lt;dtml-in getReptiles&gt;
            &lt;dtml-var species&gt;
          &lt;/dtml-in&gt;

        &lt;/dtml-with&gt;

        &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>      Another reason you might want to use the <em>with</em> 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 <em>id</em>. If you try to process this form by looking up the
      <em>id</em> variable like so:<pre>        &lt;dtml-var id&gt;</pre>
</p><p>      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 <em>with</em> tag:<pre>        &lt;dtml-with expr=&quot;REQUEST.form&quot;&gt;
          &lt;dtml-var id&gt;
        &lt;/dtml-with&gt;</pre>
</p><p>      This will ensure that you get the form's id first. See Appendix
      B for complete API documentation of the request object.</p><p>      If you submit your form without supplying a value for the <em>id</em> input,
      the form on top of the namespace stack will do you no good, since the
      form doesn't contain an <em>id</em> variable. You'll still get the client
      object's id since DTML will search the client object after failing to
      find the <em>id</em> variable in the form. The <em>with</em> tag has an attribute
      that lets you trim the DTML namespace to only include the object you
      specify:<pre>        &lt;dtml-with expr=&quot;REQUEST.form&quot; only&gt;
          &lt;dtml-if id&gt;
            &lt;dtml-var id&gt;
          &lt;dtml-else&gt;
            &lt;p&gt;The form didn't contain an &quot;id&quot; variable.&lt;/p&gt;
          &lt;/dtml-if&gt;
        &lt;/dtml-with&gt;</pre>
</p><p>      Using the <em>only</em> attribute allows you to be sure about where
      your variables are being looked up.</p><h3>    The <em>Let</em> Tag</h3>
<p>      The <em>let</em> tag lets you push a new namespace onto the namespace stack.
      This namespace is defined by the tag attributes to the <em>let</em> tag:<pre>        &lt;dtml-let person=&quot;'Bob'&quot; relation=&quot;'uncle'&quot;&gt;
          &lt;p&gt;&lt;dtml-var person&gt;'s your &lt;dtml-var relation&gt;.&lt;/p&gt;
        &lt;/dtml-let&gt;</pre>
</p><p>      This would display:<pre>        &lt;p&gt;Bob's your uncle.&lt;/p&gt;</pre>
</p><p>      The <em>let</em> tag accomplishes much of the same goals as the <em>with</em>
      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 <em>let</em> tag
      creates one or more new variables and their values and pushes a
      namespace object containing those variables and their values on
      to the top of the DTML namespace stack. In general the <em>with</em>
      tag is more useful to push existing objects onto the namespace
      stack, while the <em>let</em> tag is better suited for defining new
      variables for a block.</p><p>      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 Chapter 10, "Advanced Zope Scripting".</p><p>      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 <code>with</code> and <code>let</code> tags let you control
      the namespace to look exactly in the right place for the name you are
      looking for.</p><h2>  DTML Namespace Utility Functions </h2>
<p>    Like all things in Zope, the DTML namespace is an object, and it can
    can be accessed directly in DTML with the <em>_</em> (underscore) object.  The
    <em>_</em> namespace is often referred to as as "the under namespace".</p><p>    The under namespace provides you with many useful methods for certain
    programming tasks.  Let's look at a few of them.</p><p>    Say you wanted to print your name three times.  This can be done
    with the <em>in</em> tag, but how do you explicitly tell the <em>in</em> tag to
    loop three times?  Just pass it a sequence with three items:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;ul&gt;
      &lt;dtml-in expr=&quot;_.range(3)&quot;&gt;
        &lt;li&gt;&lt;dtml-var sequence-item&gt;: My name is Bob.&lt;/li&gt;
      &lt;/dtml-in&gt;
      &lt;/ul&gt;

      &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>    The <code>_.range(3)</code> Python expression will return a sequence of the
    first three integers, 0, 1, and 2.  The <em>range</em> function is a
    <em>standard Python built-in</em> and many of Python's built-in functions
    can be accessed through the <em>_</em> namespace, including:<dl>
<dt>      <code>range([start,], stop, [step])</code></dt>
<dd>Returns a list of integers
      from <code>start</code> to <code>stop</code> counting <code>step</code> integers at a
      time. <code>start</code> defaults to 0 and <code>step</code> defaults to 1.  For example:<pre>        '_.range(3,9,2)' -- gives '[3,5,7,9]'.

        'len(sequence)' -- 'len' returns the size of *sequence* as an integer.</pre>
</dd>
</dl>
</p><p>    Many of these names come from the Python language, which contains a set
    of special functions called <code>built-ins</code>.  The Python philosophy is to
    have a small, set number of built-in names.  The Zope philosphy can be
    thought of as having a large, complex array of built-in names.</p><p>    The under namespace can also be used to explicitly control variable
    look up.  There is a very common usage of this syntax.  You've seen
    that the in tag defines a number of special variables, like
    <em>sequence-item</em> and <em>sequence-key</em> 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?:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;h1&gt;The squares of the first three integers:&lt;/h1&gt;
      &lt;ul&gt;
      &lt;dtml-in expr=&quot;_.range(3)&quot;&gt;
        &lt;li&gt;The square of &lt;dtml-var sequence-item&gt; is: 
          &lt;dtml-var expr=&quot;sequence-item * sequence-item&quot;&gt;
        &lt;/li&gt;
      &lt;/dtml-in&gt;  
      &lt;/ul&gt;  

      &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>    Try this, does it work?  No!  Why not?  The problem lies in this
    var tag:<pre>      &lt;dtml-var expr=&quot;sequence-item * sequence-item&quot;&gt;</pre>
</p><p>    Remember, everything inside a Python expression attribute must be
    a <em>valid Python expression</em>.  In DTML, <em>sequence-item</em> is the name
    of a variable, but in Python this means "The object <em>sequence</em>
    minus the object <em>item</em>".  This is not what you want.</p><p>    What you really want is to look up the variable <em>sequence-item</em>.
    One way to solve this problem is to use the <em>in</em> tag <em>prefix</em>
    attribute. For example:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;h1&gt;The squares of the first three integers:&lt;/h1&gt;
      &lt;ul&gt;
      &lt;dtml-in prefix=&quot;loop&quot; expr=&quot;_.range(3)&quot;&gt;
        &lt;li&gt;The square of &lt;dtml-var loop_item&gt; is: 
          &lt;dtml-var expr=&quot;loop_item * loop_item&quot;&gt;
        &lt;/li&gt;
      &lt;/dtml-in&gt;  
      &lt;/ul&gt;  

      &lt;dtml-var standard_html_footer&gt;   </pre>
</p><p>    The <em>prefix</em> attribute causes <em>in</em> 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 <em>prefix</em>
    attribute.</p><p>    Another way to look up the variable <em>sequence-item</em> in a DTML
    expression is to use the <em>getitem</em> utility function to explicitly
    look up a variable:<pre>      The square of &lt;dtml-var sequence-item&gt; is:
      &lt;dtml-var expr=&quot;_.getitem('sequence-item') * 
                      _.getitem('sequence-item')&quot;&gt;</pre>
</p><p>    The <em>getitem</em> function takes the name to look up as its first
    argument. Now, the DTML Method will correctly display the sum of the
    first three integers.  The <em>getitem</em> 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 <em>getitem</em> function does not render a variable.</p><p>    Here's how to insert a rendered variable named <em>myDoc</em>:<pre>      &lt;dtml-var expr=&quot;_.getitem('myDoc', 1)&quot;&gt;</pre>
</p><p>    This example is in some ways rather pointless, since it's the
    functional equivalent to:<pre>      &lt;dtml-var myDoc&gt;</pre>
</p><p>    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 <em>selectedDoc</em> which contained the name
    of the document. You could then display the rendered document like
    so:<pre>      &lt;dtml-var expr=&quot;_.getitem(selectedDoc, 1)&quot;&gt;</pre>
</p><p>    Notice in the above example that <em>selectedDoc</em> is not in
    quotes. We don't want to insert the variable named <em>selectedDoc</em>
    we want to insert the variable <em>named by</em> <em>selectedDoc</em>. For
    example, the value of <em>selectedDoc</em> might be <em>chapterOne</em>. Using
    indirect variable insertion you can insert the <em>chapterOne</em>
    variable. This way you can insert a variable whose name you don't
    know when you are authoring the DTML. </p><p>    If you 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 <em>from</em> DTML.  This is explained more in
    Chapter 10, "Advanced Zope Scripting".  Using Python sidesteps
    many of the issues in DTML.</p><h2>  DTML Security</h2>
<p>    Zope can be used by many different kinds of users.  For example, the
    Zope site, <a href="http://www.zope.org/">Zope.org</a>, 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.</p><p>    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.</p><p>    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.</p><p>    For example, suppose you have a DTML Document named <em>Diary</em> 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:<pre>      &lt;dtml-var Diary&gt;</pre>
</p><p>    DTML verifies that the current user is authorized to access all
    DTML variables.  If the user does not have authorization, than the
    security system will raise an <em>Unauthorized</em> error and the user
    will be asked to present more privileged authentication
    credentials.</p><p>    In Chapter 7, "Users and Security" 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.</p><h3>   Safe Scripting Limits</h3>
<p>      DTML will not let you gobble up memory or execute infinite loops and
      recursions the restrictions on looping and memory are pretty tight,
      which makes DTML not the right language for complex, expensive
      programming logic.  For example, you cannot create huge lists with
      the <em>_.range</em> utility function. You also have no way to access the
      filesystem directly in DTML.</p><p>      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.</p><h2>  Advanced DTML Tags</h2>
<p>    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 web site, along with an interesting set
    of contributed DTML tags.</p><p>    This section covers what could be referred to as Zope
    <em>miscellaneous</em> tags.  These tags don't really fit into any broad
    categories except for one group of tags, the <em>exception handling</em>
    DTML tags which are discussed at the end of this chapter.</p><h2>  The <em>Call</em> Tag</h2>
<p>    The <em>var</em> tag can call methods, but it also inserts the return
    value. Using the <em>call</em> 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.</p><p>    For example, when you want to change the value of a property,
    <em>animalName</em>, you are more interested in the effect of calling the
    <em>manage_changeProperties</em> method than the return value the method
    gives you.  Here's an example:<pre>      &lt;dtml-if expr=&quot;REQUEST.has_key('animalName')&quot;&gt;
        &lt;dtml-call expr=&quot;manage_changeProperties(animalName=REQUEST['animalName'])&quot;&gt;
        &lt;h1&gt;The property 'animalName' has changed&lt;/h1&gt;
      &lt;dtml-else&gt;
        &lt;h1&gt;No properties were changed&lt;/h1&gt;
      &lt;/dtml-if&gt;</pre>
</p><p>    In this example, the page will change a property depending on whether
    a certain name exists.  The result of the <em>manage_changeProperties</em>
    method is not important and does not need to be shown to the user.</p><p>    Another common usage of the <em>call</em> tag is calling methods that affect
    client behavior, like the <code>RESPONSE.redirect</code> 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 <em>let</em> tag:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;dtml-let target=&quot;'http://example.com/new_location.html'&quot;&gt;

        &lt;h1&gt;This page has moved, you will now be redirected to the
        correct location.  If your browser does not redirect, click &lt;a
        href=&quot;&lt;dtml-var target&gt;&quot;&gt;&lt;dtml-var target&gt;&lt;/a&gt;.&lt;/h1&gt;

        &lt;dtml-call expr=&quot;RESPONSE.redirect(target)&quot;&gt;

      &lt;/dtml-let&gt;

      &lt;dtml-var standard_html_footer&gt;  </pre>
</p><p>    In short, the <em>call</em> tag works exactly like the <em>var</em> tag with the
    exception that it doesn't insert the results of calling the
    variable.</p><h2>  The <em>Comment</em> Tag</h2>
<p>    DTML can be documented with comments using the <em>comment</em> tag:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;dtml-comment&gt;

        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.

      &lt;/dtml-comment&gt;

      &lt;!-- 

        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.

      --&gt;

      &lt;dtml-var standard_html_footer&gt;        </pre>
</p><p>    The <em>comment</em> block is removed from DTML output.</p><p>    In addition to documenting DTML you can use the <em>comment</em> tag to
    temporarily comment out other DTML tags. Later you can remove the
    <em>comment</em> tags to re-enable the DTML.</p><h2>  The <em>Tree</em> Tag</h2>
<p>    The <em>tree</em> tag lets you easily build dynamic trees in HTML to
    display hierarchical data.  A <em>tree</em> 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.</p><p>    For example here's a tree that represents a collection of folders
    and sub-folders.</p><p>    <a name="7-5"></a>
<img src="Figures/7-5.png" alt="HTML tree generated by the tree tag.">
<p><b>Figure 7-5</b> HTML tree generated by the tree tag.</p>
</p><p>    Here's the DTML that generated this tree display:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;dtml-tree&gt;

        &lt;dtml-var getId&gt;

      &lt;/dtml-tree&gt;

      &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>    The <em>tree</em> tag queries objects to find their sub-objects and takes
    care of displaying the results as a tree. The <em>tree</em> tag block works
    as a template to display nodes of the tree.</p><p>    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 <em>cookie</em>.  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.</p><p>    You can tailor the behavior of the <em>tree</em> tag quite a bit with <em>tree</em>
    tag attributes and special variables. Here is a sampling of <em>tree</em>
    tag attributes.<dl>
<dt>      branches</dt>
<dd>The name of the method used to find sub-objects. This
      defaults to <em>tpValues</em>, which is a method defined by a number of
      standard Zope objects.</dd>
<dt>      leaves</dt>
<dd>The name of a method used to display objects that do
      not have sub-object branches.</dd>
<dt>      nowrap</dt>
<dd>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.</dd>
<dt>      sort</dt>
<dd>Sort branches before text insertion is performed. The
      attribute value is the name of the attribute that items should be
      sorted on.</dd>
<dt>      assume_children</dt>
<dd>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.</dd>
<dt>      single</dt>
<dd>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.</dd>
<dt>      skip_unauthorized</dt>
<dd>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.</dd>
</dl>
</p><p>    Suppose you want to use the <em>tree</em> 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.</p><p>    Let's first define a Script with the id of <em>publicObjects</em>
    that returns public objects:<pre>      ## Script (Python) &quot;publicObjects&quot;
      ##
      &quot;&quot;&quot;
      Returns sub-folders and DTML documents that have a
      true 'siteMap' property.
      &quot;&quot;&quot;
      results=[]
      for object in context.objectValues(['Folder', 'DTML Document']):
          if object.hasProperty('siteMap') and object.siteMap:
              results.append(object)
      return results</pre>
</p><p>    Now we can create a DTML Method that uses the <em>tree</em> tag and our
    Scripts to draw a site map:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;h1&gt;Site Map&lt;/h1&gt;

      &lt;p&gt;&lt;a href=&quot;&amp;dtml-URL0;?expand_all=1&quot;&gt;Expand All&lt;/a&gt; |
         &lt;a href=&quot;&amp;dtml-URL0;?collapse_all=1&quot;&gt;Collapse All&lt;/a&gt;
      &lt;/p&gt;

      &lt;dtml-tree branches=&quot;publicObjects&quot; skip_unauthorized=&quot;1&quot;&gt;
        &lt;a href=&quot;&amp;dtml-absolute_url;&quot;&gt;&lt;dtml-var title_or_id&gt;&lt;/a&gt;
      &lt;/dtml-tree&gt;

      &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>    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.</p><p>    <a name="7-6"></a>
<img src="Figures/7-6.png" alt="Dynamic site map using the tree tag.">
<p><b>Figure 7-6</b> Dynamic site map using the tree tag.</p>
</p><p>    For a summary of the <em>tree</em> tag arguments and special variables see
    Appendix A.</p><h2>  The <em>Return</em> Tag</h2>
<p>    In general DTML creates textual output. You can however, make DTML
    return other values besides text. Using the <em>return</em> tag you can
    make a DTML Method return an arbitrary value just like a Python or
    Perl-based Script.</p><p>    Here's an example:<pre>      &lt;p&gt;This text is ignored.&lt;/p&gt;

      &lt;dtml-return expr=&quot;42&quot;&gt;</pre>
</p><p>    This DTML Method returns the number 42.</p><p>    Another upshot of using the <em>return</em> tag is that DTML execution
    will stop after the <em>return</em> tag.</p><p>    If you find yourself using the <em>return</em> tag, you almost certainly
    should be using a Script instead. The <em>return</em> tag was developed
    before Scripts, and is largely useless now that you can easily
    write scripts in Python and Perl.</p><h2>  The <em>Sendmail</em> Tag</h2>
<p>    The <em>sendmail</em> tag formats and sends a mail messages. You can use
    the <em>sendmail</em> tag to connect to an existing Mail Host, or you can
    manually specify your SMTP host.</p><p>    Here's an example of how to send an email message with the
    <em>sendmail</em> tag:<pre>      &lt;dtml-sendmail&gt;
      To: &lt;dtml-var recipient&gt;
      Subject: Make Money Fast!!!!

      Take advantage of our exciting offer now! Using our exclusive method
      you can build unimaginable wealth very quickly. Act now!
      &lt;/dtml-sendmail&gt;</pre>
</p><p>    Notice that there is an extra blank line separating the mail
    headers from the body of the message.</p><p>    A common use of the <em>sendmail</em> tag is to send an email message
    generated by a feedback form. The <em>sendmail</em> tag can contain any
    DTML tags you wish, so it's easy to tailor your message with form
    data.</p><h2>  The <em>Mime</em> Tag</h2>
<p>    The <em>mime</em> 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 <em>mime</em> tag you can use
    Zope to send emails with attachments.</p><p>    Suppose you'd like to upload your resume to Zope and then have Zope
    email this file to a list of potential employers.</p><p>    Here's the upload form:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;p&gt;Send you resume to potential employers&lt;/p&gt;

      &lt;form method=post action=&quot;sendresume&quot; ENCTYPE=&quot;multipart/form-data&quot;&gt;
      &lt;p&gt;Resume file: &lt;input type=&quot;file&quot; name=&quot;resume_file&quot;&gt;&lt;/p&gt;
      &lt;p&gt;Send to:&lt;/p&gt;
      &lt;p&gt;
      &lt;input type=&quot;checkbox&quot; name=&quot;send_to:list&quot; value=&quot;jobs@yahoo.com&quot;&gt;
        Yahoo&lt;br&gt;

      &lt;input type=&quot;checkbox&quot; name=&quot;send_to:list&quot; value=&quot;jobs@microsoft.com&quot;&gt;
        Microsoft&lt;br&gt;

      &lt;input type=&quot;checkbox&quot; name=&quot;send_to:list&quot; value=&quot;jobs@mcdonalds.com&quot;&gt;
        McDonalds&lt;/p&gt;

      &lt;input type=submit value=&quot;Send Resume&quot;&gt;
      &lt;/form&gt;

      &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>    Create another DTML Method called <em>sendresume</em> to process the form
    and send the resume file:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;dtml-if send_to&gt;

        &lt;dtml-in send_to&gt; 

          &lt;dtml-sendmail smtphost=&quot;my.mailserver.com&quot;&gt;
          To: &lt;dtml-var sequence-item&gt;
          Subject: Resume
          &lt;dtml-mime type=text/plain encode=7bit&gt;

          Hi, please take a look at my resume.

          &lt;dtml-boundary type=application/octet-stream disposition=attachment 
          encode=base64&gt;&lt;dtml-var expr=&quot;resume_file.read()&quot;&gt;&lt;/dtml-mime&gt;
          &lt;/dtml-sendmail&gt;

        &lt;/dtml-in&gt;

        &lt;p&gt;Your resume was sent.&lt;/p&gt;

      &lt;dtml-else&gt;

        &lt;p&gt;You didn't select any recipients.&lt;/p&gt;

      &lt;/dtml-if&gt;

      &lt;dtml-var standard_html_footer&gt;    </pre>
</p><p>    This method iterates over the <em>sendto</em> variable and sends one
    email for each item.</p><p>    Notice that there is no blank line between the <code>To:</code> header and
    the starting <em>mime</em> tag.  If a blank line is inserted between them
    then the message will not be interpreted as a <em>multipart</em> message
    by the receiving mail reader.</p><p>    Also notice that there is no newline between the <em>boundary</em> tag
    and the <em>var</em> tag, or the end of the <em>var</em> tag and the closing
    <em>mime</em> 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.</p><p>    As per the MIME spec, <em>mime</em> tags may be nested within <em>mime</em> tags
    arbitrarily.</p><h2>  The <em>Unless</em> Tag</h2>
<p>    The <em>unless</em> tag executes a block of code unless the given condition is
    true. The <em>unless</em> tag is the opposite of the <em>if</em> tag.  The DTML
    code:<pre>      &lt;dtml-if expr=&quot;not butter&quot;&gt;
        I can't believe it's not butter.
      &lt;/dtml-if&gt;</pre>
</p><p>    is equivalent to:<pre>      &lt;dtml-unless expr=&quot;butter&quot;&gt;
        I can't believe it's not butter.
      &lt;/dtml-unless&gt;</pre>
</p><p>    What is the purpose of the <em>unless</em> tag? It is simply a convenience
    tag. The <em>unless</em> tag is more limited than the <em>if</em> tag, since it
    cannot contain an <em>else</em> or <em>elif</em> tag.</p><p>    Like the <em>if</em> tag, calling the <em>unless</em> tag by name does existence
    checking, so:<pre>      &lt;dtml-unless the_easter_bunny&gt;
        The Easter Bunny does not exist or is not true.
      &lt;/dtml-unless&gt;</pre>
</p><p>    Checks for the existence of <em>the_easter_bunny</em> as well as its
    truth. While this example only checks for the truth of
    <em>the_easter_bunny</em>:<pre>      &lt;dtml-unless expr=&quot;the_easter_bunny&quot;&gt;
        The Easter Bunny is not true.
      &lt;/dtml-unless&gt;</pre>
</p><p>    This example will raise an exception if <em>the_easter_bunny</em> does not
    exist.</p><p>    Anything that can be done by the <em>unless</em> tag can be done by the
    <em>if</em> tag.  Thus, its use is totally optional and a matter of
    style.</p><h2>  Batch Processing With The <em>In</em> Tag</h2>
<p>    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
    <em>batching</em>. Batching has a number of benefits.<ul>
<li>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.</li>
<li>Because smaller batches of results are being used, often less
      memory is consumed by Zope.</li>
<li><em>Next</em> and <em>Previous</em> navigation interfaces makes scanning
      large batches relatively easy.</li>
</ul>
</p><p>    The <em>in</em> 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:<pre>      &lt;dtml-var standard_html_header&gt;

        &lt;dtml-in expr=&quot;_.range(100)&quot; size=10 start=query_start&gt;

          &lt;dtml-if sequence-start&gt;

            &lt;dtml-if previous-sequence&gt;
              &lt;a href=&quot;&lt;dtml-var URL&gt;&lt;dtml-var sequence-query
                 &gt;query_start=&lt;dtml-var previous-sequence-start-number&gt;&quot;&gt;
                 (Previous &lt;dtml-var previous-sequence-size&gt; results)
              &lt;/a&gt;
            &lt;/dtml-if&gt;

            &lt;h1&gt;These words are displayed at the top of a batch:&lt;/h1&gt;
            &lt;ul&gt;

          &lt;/dtml-if&gt;

            &lt;li&gt;Iteration number: &lt;dtml-var sequence-item&gt;&lt;/li&gt;

          &lt;dtml-if sequence-end&gt;

            &lt;/ul&gt;
            &lt;h4&gt;These words are displayed at the bottom of a batch.&lt;/h4&gt;

            &lt;dtml-if next-sequence&gt;
               &lt;a href=&quot;&lt;dtml-var URL&gt;&lt;dtml-var sequence-query
                  &gt;query_start=&lt;dtml-var
                  next-sequence-start-number&gt;&quot;&gt;
               (Next &lt;dtml-var next-sequence-size&gt; results)
               &lt;/a&gt;

            &lt;/dtml-if&gt;

          &lt;/dtml-if&gt;

        &lt;/dtml-in&gt;

      &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>    Let's take a look at the DTML to get an idea of what's going
    on. First we have an <em>in</em> tag that iterates over 100 numbers that
    are generated by the <em>range</em> utility function. The <em>size</em>
    attribute tells the <em>in</em> tag to display only 10 items at a
    time. The <em>start</em> attribute tells the <em>in</em> tag which item number
    to display first.</p><p>    Inside the <em>in</em> tag there are two main <em>if</em> tags. The first one
    tests special variable <code>sequence-start</code>. 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 <em>if</em> tag tests for the special variable
    <code>sequence-end</code>. This variable is only true on the last pass
    through the <em>in</em> tag. So the second <em>if</em> block will only be
    executed once at the end.  The paragraph between the <em>if</em> tags is
    executed each time through the loop.</p><p>    Inside each <em>if</em> tag there is another <em>if</em> tag that check for the
    special variables <code>previous-sequence</code> and <code>next-sequence</code>. The
    variables are true when the current batch has previous or further
    batches respectively. In other words <code>previous-sequence</code> is true
    for all batches except the first, and <code>next-sequence</code> 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.</p><p>    The batch navigation consists of links back to the document with a
    <em>query_start</em> variable set which indicates where the <em>in</em> 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.</p><p>    Finally some statistics about the previous and next batches are
    displayed using the <code>next-sequence-size</code> and
    <code>previous-sequence-size</code> special variables.  All of this ends up
    generating the following HTML code:<pre>      &lt;html&gt;&lt;head&gt;&lt;title&gt;Zope&lt;/title&gt;&lt;/head&gt;&lt;body bgcolor=&quot;#FFFFFF&quot;&gt;

        &lt;h1&gt;These words are displayed at the top of a batch:&lt;/h1&gt;
        &lt;ul&gt;
          &lt;li&gt;Iteration number: 0&lt;/li&gt;
          &lt;li&gt;Iteration number: 1&lt;/li&gt;
          &lt;li&gt;Iteration number: 2&lt;/li&gt;
          &lt;li&gt;Iteration number: 3&lt;/li&gt;
          &lt;li&gt;Iteration number: 4&lt;/li&gt;
          &lt;li&gt;Iteration number: 5&lt;/li&gt;
          &lt;li&gt;Iteration number: 6&lt;/li&gt;
          &lt;li&gt;Iteration number: 7&lt;/li&gt;
          &lt;li&gt;Iteration number: 8&lt;/li&gt;
          &lt;li&gt;Iteration number: 9&lt;/li&gt;
        &lt;/ul&gt;
        &lt;h4&gt;These words are displayed at the bottom of a batch.&lt;/h4&gt;

           &lt;a href=&quot;http://pdx:8090/batch?query_start=11&quot;&gt;
             (Next 10 results)
           &lt;/a&gt;

      &lt;/body&gt;&lt;/html&gt;</pre>
</p><p>    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 Chapter 11, "Searching and
    Categorizing Content".</p><h2>  Exception Handling Tags</h2>
<p>    Zope has extensive exception handling facilities. You can get
    access to these facilities with the <em>raise</em> and <em>try</em> tags. For more
    information on exceptions and how they are raised and handled see
    a book on Python or you can read the online <a href="http://www.python.org/doc/current/tut/node10.html">Python
    Tutorial</a>.</p><h3>    The <em>Raise</em> Tag</h3>
<p>      You can raise exceptions with the <em>raise</em> tag. One reason to raise
      exceptions is to signal an error. For example you could check
      for a problem with the <em>if</em> tag, and in case there was something
      wrong you could report the error with the <em>raise</em> tag.</p><p>      The <em>raise</em> 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
      <em>Unauthorized</em> and <em>Redirect</em> that are returned as HTTP
      errors. <em>Unauthorized</em> 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:<pre>        &lt;dtml-raise type=&quot;404&quot;&gt;Not Found&lt;/dtml-raise&gt;</pre>
</p><p>      This raises an HTTP 404 (Not Found) error. Zope responds by
      sending the HTTP 404 error back to the client's browser.</p><p>      The <em>raise</em> tag is a block tag. The block enclosed by the
      <em>raise</em> 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.</p><p>      Here is a <em>raise</em> tag example:<pre>        &lt;dtml-if expr=&quot;balance &gt;= debit_amount&quot;&gt;

          &lt;dtml-call expr=&quot;debitAccount(account, debit_amount)&quot;&gt;

          &lt;p&gt;&lt;dtml-var debit_amount&gt; has been deducted from your
          account &lt;dtml-var account&gt;.&lt;/p&gt;

        &lt;dtml-else&gt;

          &lt;dtml-raise type=&quot;Insufficient funds&quot;&gt;

            &lt;p&gt;There is not enough money in account &lt;dtml-account&gt; 
            to cover the requested debit amount.&lt;/p&gt;

          &lt;/dtml-raise&gt;

        &lt;/dtml-if&gt;</pre>
</p><p>      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 to be ignored. So in
      addition to reporting errors, exceptions allow you to back out
      changes if a problem crops up.</p><h3>    The <em>Try</em> Tag</h3>
<p>      If an exception is raised either manually with the <em>raise</em> tag, or
      as the result of some error that Zope encounters, you can catch
      it with the <em>try</em> tag.</p><p>      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:<pre>        Cost per unit: &lt;dtml-var
                             expr=&quot;_.float(total_cost/total_units)&quot; 
                             fmt=dollars-and-cents&gt;</pre>
</p><p>      This DTML works fine if <em>total_units</em> is not zero. However, if
      <em>total_units</em> is zero, a <em>ZeroDivisionError</em> exception is raised
      indicating an illegal operation. So rather than rendering the
      DTML, an error message will be returned.</p><p>      You can use the <em>try</em> tag to handle these kind of problems. With
      the <em>try</em> tag you can anticipate and handle errors yourself,
      rather than getting a Zope error message whenever an exception
      occurs.</p><p>      The <em>try</em> tag has two functions. First, if an exception is raised,
      the <em>try</em> tag gains control of execution and handles the exception
      appropriately, and thus avoids returning a Zope error
      message. Second, the <em>try</em> tag allows the rendering of any
      subsequent DTML to continue.</p><p>      Within the <em>try</em> tag are one or more <em>except</em> tags that identify and
      handle different exceptions. When an exception is raised, each
      <em>except</em> tag is checked in turn to see if it matches the
      exception's type. The first <em>except</em> tag to match handles the
      exception. If no exceptions are given in an <em>except</em> tag, then the
      <em>except</em> tag will match all exceptions.</p><p>      Here's how to use the <em>try</em> tag to avoid errors that could occur
      in the last example:<pre>        &lt;dtml-try&gt;

          Cost per unit: &lt;dtml-var 
                               expr=&quot;_.float(total_cost/total_units)&quot;
                               fmt=&quot;dollars-and-cents&quot;&gt;

        &lt;dtml-except ZeroDivisionError&gt; 

          Cost per unit: N/A 

        &lt;/dtml-try&gt; </pre>
</p><p>      If a <em>ZeroDivisionError</em> is raised, control goes to the <em>except</em>
      tag, and "Cost per unit: N/A" is rendered. Once the except tag
      block finishes, execution of DTML continues after the <em>try</em> block.</p><p>      DTML's <em>except</em> 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 <em>ArithmeticError</em> is named in a <em>except</em> tag, the
      tag can handle all <em>ArithmeticError</em> subclasses including,
      <em>ZeroDivisionError</em>. See a Python reference such as the online
      <a href="http://www.python.org/doc/current/lib/module-exceptions.html">Python Library
      Reference</a>
      for a list of Python exceptions and their subclasses.  An
      <em>except</em> tag can catch multiple exceptions by listing them all
      in the same tag.</p><p>      Inside the body of an <em>except</em> tag you can access information
      about the handled exception through several special
      variables.<dl>
<dt>        <em>error_type</em></dt>
<dd>The type of the handled exception. </dd>
<dt>        <em>error_value</em></dt>
<dd>The value of the handled exception.</dd>
<dt>        <em>error_tb</em></dt>
<dd>The traceback of the handled exception.</dd>
</dl>
</p><p>      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.</p><h4>      The <em>Try</em> Tag Optional <em>Else</em> Block</h4>
<p>        The <em>try</em> tag has an optional <em>else</em> block that is rendered if an
        exception didn't occur.  Here's an example of how to use the
        <em>else</em> tag within the try tag:<pre>          &lt;dtml-try&gt; 

            &lt;dtml-call feedAlligators&gt;

          &lt;dtml-except NotEnoughFood WrongKindOfFood&gt;

            &lt;p&gt;Make sure you have enough alligator food first.&lt;/p&gt;

          &lt;dtml-except NotHungry&gt; 

            &lt;p&gt;The alligators aren't hungry yet.&lt;/p&gt;

          &lt;dtml-except&gt; 

            &lt;p&gt;There was some problem trying to feed the alligators.&lt;p&gt;
            &lt;p&gt;Error type: &lt;dtml-var error_type&gt;&lt;/p&gt;
            &lt;p&gt;Error value: &lt;dtml-var error_value&gt;&lt;/p&gt;

          &lt;dtml-else&gt; 

            &lt;p&gt;The alligator were successfully fed.&lt;/p&gt;

          &lt;/dtml-try&gt; </pre>
</p><p>        The first <em>except</em> block to match the type of error raised is
        rendered. If an <em>except</em> block has no name, then it matches all
        raised errors. The optional <em>else</em> block is rendered when no
        exception occurs in the <em>try</em> block. Exceptions in the <em>else</em>
        block are not handled by the preceding <em>except</em> blocks.</p><h4>      The <em>Try</em> Tag Optional <em>Finally</em> Block</h4>
<p>        You can also use the <em>try</em> tag in a slightly different
        way. Instead of handling exceptions, the <em>try</em> tag can be used
        not to trap exceptions, but to clean up after them.</p><p>        The <em>finally</em> tag inside the <em>try</em> tag specifies a cleanup block
        to be rendered even when an exception occurs.</p><p>        The <em>finally</em> block is only useful if you need to clean up
        something that will not be cleaned up by the transaction abort
        code. The <em>finally</em> block will always be called, whether there
        is an exception or not and whether a <em>return</em> tag is used or
        not. If you use a <em>return</em> tag in the try block, any output of
        the <em>finally</em> block is discarded. Here's an example of how you
        might use the <em>finally</em> tag:<pre>          &lt;dtml-call acquireLock&gt;  
          &lt;dtml-try&gt;
              &lt;dtml-call useLockedResource&gt;
          &lt;dtml-finally&gt;
              &lt;!-- this always gets done even if an exception is raised --&gt;
              &lt;dtml-call releaseLock&gt;
          &lt;/dtml-try&gt;</pre>
</p><p>        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 <em>try</em> block by
        executing the <em>finally</em> block.</p><p>        The <em>try/finally</em> form of the <em>try</em> tag is seldom used in
        Zope. This kind of complex programming control is often better
        done in Python or Perl.</p><h2>  Conclusion</h2>
<p>    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.</p><p>    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.</p></body>
</html>