Code Concepts 101: Using Logic in Zope's DTML
DTML can be confusing until you learn some of the basic ideas and encounter the "rough spots." This article explains some strategies that you can use to apply DTML's built-in flow control and logical decision-making capabilities. The objective is to create dynamic web pages that know what to display in different circumstances. To begin, create a DTML method object with an ID of standard_dtml_wrapper and a title of Site Wrapper Method, as shown in Listing 1.
Listing 1: A "Wrapper" DTML Method
01 <HTML> 02 <HEAD> 03 <TITLE><dtml-var title></TITLE> 04 </HEAD> 05 <BODY> 06 <dtml-var banner> 07 <dtml-var expr="_[page_body]" fmt=structured-text> 08 </BODY> 09 </HTML>
Notice line 07, which says fmt=structured-text. That is the notation that activates the filter to convert from structured text to HTML.
You will refine the wrapper as the exercise progresses.
Next create an Image object called banner_logo that contains the image that you'd like to use as a banner for your site. You won't see a reference to the logo image in the wrapper because it is really "part of" the banner. Create your banner object as a DTML method with the ID of banner and the title Site Banner. This time, replace the default text with this line:
<dtml-var banner_logo><h1><dtml-var title></h1>
You might be surprised that the reference to banner_logo doesn't specify the image size, or even the fact that the element is an image. Zope handles all of that for you because you created the object as an image type. In some cases, you might need to specify a width and height if you want to scale the image differently from its original dimensions. Notice that the banner text is simply the title of the MyHome.html object, which has been rendered as a heading.
More DTML Options: Process Flow Control
A value stored as a variable can be created at one point in a process and referred to at some later point. This is truly the most basic aspect of computer programming, but it might be new to some readers who have been working primarily with conventional HTML and graphics. Things really get interesting when the process itself relies on the stored value to determine which one of a set of possible actions to carry out. This is a type of automation being put to work in the creation of dynamic web pages.
Branching: A Fork in the Decision Tree
Consider the variable page_body, which serves to identify the unique page content of this example. The standard_dtml_wrapper is written so that it assumes that this variable has been assigned. The example is simple and easy to understand, which suited your needs, but it is not comprehensive. What would happen if a call were made to the wrapper method, but the variable didn't yet exist? You will see the Zope error screen often enough, so start applying a bit of prevention right now. Select standard_dtml_wrapper from the site_folder.
You need to add a logical "branch," a decision point where Zope can check to see if the variable has been set. That way, the process can continue normally when all goes well, but it can carry out default behavior in case of an omission.
The new DTML syntax that you will use is called <dtml-if>, and it can be inserted into the existing dtml method object standard_dtml_wrapper, as seen in Listing 2.
Listing 2: Adding a Branch to the Wrapper
01 <html> 02 <head> 03 <title><dtml-var title_or_id></title> 04 <head> 05 <body> 06 <dtml-var banner> 07 <dtml-if page_body> 08 <dtml-var "_[page_body]" fmt=structured-text> 09 <dtml-else> 10 <dtml-var default_page> 11 </dtml-if> 12 </body> 13 </html>
The tag at line 07, <dtml-if page_body>, simply checks to see that a variable with the name page_body exists. The <dtml-if> asks ZPublisher to confirm whether calling an object named page_body results in a nonempty value, which, in code lingo, is interpreted as true. If so, the next line carries on as before, but the <dtml-else> line allows for the possibility that the result was false, such as when the variable does not exist. If that happens, the line after <dtml-else> will be carried out.
Of course, now you have to create a default_page object that will always be available for such contingencies. In this case, the new object could be a document that displays a line of text saying something like, "The page you requested is not available at this time." At least that would be more polite and considerate than an alarming "ERROR!" message. Go ahead and create a DTML document with an ID of default_page and a title of Default Error Massage, and replace the template text with the message of your choice. You can improve it as you gain expertise, but at least it will work well enough for now.
Looping: Doing It Until It's Done
Another basic flow-control construct is known as a loop. Loops enable iteration over a set of elements so that each one is processed in turn. For example, the cases that were allowed for in the previous code allow only two possible objects for insertion into a page after the banner. Another approach might be to create a list of possible object names and test for each one from the most common to the least. While cumbersome, this idea could come in handy when you have a set of possible conditions that is neither too short nor too long in number. If you need a name to help you remember this sort of judgment call, which arises frequently in the programming field, you could call it the "Goldilocks Principle" (as in "too hot, too cold, just right"). The choices that programmers make are less often the consistent application of clear-cut "laws" as much as "guesstimates" that are arrived at through experience and personal preference.
The most-used loop construct in DTML is <dtml-in sequence_name>, which applies a template or process to each item that is "in" a set if items. You will be using <dtml-in> loops frequently, especially when working with databases and queries.
You might be thinking of any number of other ways to handle this. So, take a look at one more variation of this methodthis time with two branches, one "nested" inside anotherwith the text in Listing 3.
Listing 3: Choosing One of Three Options
01 <html> 02 <head> 03 <title><dtml-var title_or_id></title> 04 <head> 05 <body> 06 <dtml-var banner> 07 <dtml-if page_body> 08 <dtml-if "page_body[-4:]=='.stx'"> 09 <dtml-var "_[page_body]" fmt=structured-text> 10 <dtml-else> 11 <dtml-var "_[page_body]"> 12 </dtml-if> 13 <dtml-else> 14 <dtml-var default_page> 15 </dtml-if> 16 </body> 17 </html>
The new case that you are handling in Listing 3 covers the possibility that the page_body variable names an object that isn't formatted as structured_text. An example of this case is an existing HTML page that has been adapted so that it can be wrapped and used on this new site. Line 08 in this version, <dtml-if "page_body[-4:]==.stx'">, tests whether the value stored as page_body has the string ".stx" as the last four characters. The brackets, -4, and colon are an example of the "slice syntax" used in Python.
The number and colon in this example mean, "all the characters in this string, from the fourth from the last, to the end."
Knowing Python Helps You Understand Zope
Many articles about Zope, beginners tutorials, and helpful Zope users will assure you that mastery of Python isn't required to use Zope effectively. However, plenty of enthusiastic Python coders got their first glimpse of Python when they tried Zope. No one will dispute the fact that the more Python you know, the easier it will be to get the most out of Zope.
So, don't let the fact that you can indeed use Zope without really understanding Python keep you from adding this powerful and popular language to your toolkit. Especially if you are new to programming, look no further than Python. Python is famous for both its approachability and its practical usefulness.
To start your Python explorations, see any of the excellent tutorials listed at these links:
Zope is nearly all Python codeand not by accident. When the Zope folks chose Python, they did so because they knew that the benefits of a language steeped in object-oriented concepts with unmatched clarity and ease of use would empower Zope to support challenging and sophisticated web development projects. Python's capability to run on a wide range of hardware and software platforms is another essential ingredient. The web is only beginning to demonstrate the need to accommodate diverse and unanticipated uses, from cell phones and handhelds to smart cars and global satellite systems. Even if your projects don't demand absolute state-of-the-art technology, it can be very comforting to know that "it's in there."
A bit of explanation is in order regarding the specifics of the references to the variable page_body at different points in the standard_dtml_wrapper in Listing 3. Sometimes it's in quotes, and sometimes not. Sometimes it's in brackets but is not quoted. Looking back at the original instance, recall that the variable is assigned with the name of the object enclosed in single quotes and then is double-quoted as well. This all looks mysterious, and it certainly takes some of getting used to, but hang in there. We'll go through each caseand then show you how to totally bypass the worst of it altogether with a wonderful new feature called Python Scripts that appeared in Zope as of Version 2.3.