Creating Basic Zope Applications

XXX - this chapter is not done. I got to just before "Factoring Out Stylesheets" and quit for now. The material prior to that needs to be expanded and cleaned up as well. The examples also need to be converted to page templates. -chrism

In this chapter you'll learn more about building basic web applications in Zope using Folders, Scripts, and Methods. Another way of terming this is that you'll learn more about creating applications in Zope "instance space".

Building "Instance-Space" Applications

In Zope, there are a few ways to develop a web application. The simplest and fastest way, and the one we've been concentrating on thus far in this book, is to build an application in instance space. To understand the term "instance space", we need to once again put on our "object orientation hats".

When you create Zope objects by selecting them from the Zope "Add" list, you are creating instances of a class defined by someone else (see the Object Orientation chapter if you need to brush up on these terms). For example, when you add a Script (Python) object to your Zope database, you are creating an instance of the Script (Python) class. The Script (Python) class was written by a Zope Corporation engineer. When you select "Script (Python)" from the Add list, and you fill in the form to give an id and title and whatnot, and click the submit button on the form, Zope creates an instance of that class in the Folder of your choosing. Instances such as these are inserted into your Zope database and they live there until you delete them.

In the Zope application server, most object instances serve to perform presentation duties, logic duties, or content duties. You can "glue" these instances together to create basic Zope applications. Since these objects are really instances of a class, the term "instance space" is commonly used to describe the Zope root folder and all of its subfolders. "Building an application in instance space" is defined as the act of creating Zope object instances in this space and modifying them to act a certain way when they are executed.

Instance-space applications are typically created from common Zope objects. Script (Python) objects, Folders, DTML Methods, Page Templates, and other Zope services can be glued together to build simple applications.

Instance-Space Applications vs. Products

In contrast to building applications in instance space, you may also build applications in Zope by building them as Products. Building an application as a Product differs from creating applications in instance space inasmuch as the act of creating a Product typically allows you to extend Zope with new "addable" objects that appear in Zope's "Add" list. Building a Product also typically allows you to more easily distribute an application to other people, and allows you to build objects that may more closely resemble your "problem space". We explore one way to create Products in the chapter entitled Extending Zope. Building a Product is typically more complicated than building an "instance-space" application, so we get started here by describing how to build instance-space applications. When you find that it becomes difficult to maintain, extend, or distribute an instance-space application you've written, it's probably time to reconsider rewriting it as a Product.

Using A Folder as A Container For Your Instance-Space Application

Folders provide containers for your applications. A natural way to build a simple Zope application is to create a Folder in your Zope root folder to hold objects related to the application. For example, you may have an Invoices folder to hold an invoice application. You could create "logic" objects inside that folder named addInvoice and editInvoice to allow you to add and edit the invoices. The actual invoices themselves could be DTML Documents or File objects, which could also live in the Invoices folder. Your Invoices folder thus becomes a small application.

URLs are used to work with instance-space Zope applications. As you've seen, you can display a Zope object by visiting its URL in your browser, and in object-orientation terms, when you visit an object in a folder, you are "calling a method in the context of the folder". So for example, the URL http://localhost:8080/Invoices/addInvoice calls the addInvoice method of the Invoices folder. This URL would perhaps take you to a screen that allows you to add an invoice. Likewise, the URL http://localhost:8080/Invoices/editInvoice?invoice_number=42 might call the editInvoice method of the Invoices folder, passing it the argument invoice_number with a value of 42. The resulting HTML might allow you to edit invoice number 42.

Using Objects as Methods Of Folders Via URLs

The invoices example demonstrates a powerful Zope feature. You can execute a Zope object in the context of a folder by visiting a URL that consists of the folder's URL followed by the id of a Zope object. For example, in the URL http://localhost:8080/Invoices/addInvoice, the name Invoices refers to a folder. In object-orientation terms, the "final" object in the URL ('addInvoice') is then used as a "method". The object you call which is used as a method may be a Script (Python) object, a DTML Method, a Page Template, or just about any other kind of Zope object.

This facility is used throughout Zope and is a very general design pattern. In fact you are not restricted to using a folder as the context of a method via a URL. You may call objects as methods in the context of many kinds of Zope objects using the same URL technique.

Using Acquisition In Instance-Space Applications

The Zope facility named Acquisition proves useful when creating instance-space applications. Acquisition allows you to share behavior between different parts of the same application. A folder is said to acquire an object by searching for the object in its containers if it cannot find the object by name in itself.

For example, suppose you want to call a method named viewFolder on one of your folders. Perhaps you have many different viewFolder objects which can be used as methods, each of which represents a particular view of a folder. Zope "figures out" which one you want by first looking in the folder which is named by the "rightmost" portion of the URL. For example, if you invoke the URL http://localhost:8080/Invoices/July/viewFolder, and the "Invoices" and "July" objects are folders, the invoices object will be searched for a viewFolder object first. If Zope can't find the object there it looks for an object named viewFolder in the folder's containing folder ('July'). If the object can't be found there, it goes up another level. This process continues until Zope finds the object or gets to the root folder. If Zope can't find the object in the root it gives up and raises an exception.

The Special Folder Object index_html

If there is an object in a Zope folder named index_html, the return value of this object will be used as the default view of the folder when the folder's URL is called. This is analogous to how an index.html file provides a default view for a directory in Apache and other web servers. Instead of explicitly including the name index_html in your URL to show default content for a folder, you can omit it. For example, if you create an index_html object in your Invoices folder and view the folder by clicking the View tab or by visiting the URL http://localhost:8080/Invoices/, Zope will call the index_html object in the Invoices folder and display its results. You can also use the more explicit URL http://localhost:8080/Invoices/index_html, and it will display the same content.

A folder can also acquire an index_html object from its parent folders. You can use this behavior to create a default view for a set of folders. To do so, create an index_html object in a folder which contains another set of folders. This default view will be used for all the folders in the set. This behavior is already evident in Zope. If you create a set of empty Folders in the Zope root folder, you will notice that when you view any of the Folders via a URL, the content of the "root" folder's index_html method is displayed. The index_html in the root folder is acquired. Furthermore, if you create more empty folders inside the folders you've just created in the root folder, a visit to these folders' URLs will also show the root folder's index_html. This is acquisition at work. NOTE: We are using the index_html method as an example here, but this will work with any Zope object which acts as a method, it needs not be named "index_html".

If you want a different default view of a given folder, just create a custom index_html object in that particular folder. This allows you to override the default view of a particular folder on a case-by-case basis, while allowing other folders defined at the same level to acquire a common default view.

The index_html object may be a DTML Method, a Page Template, a Script (Python) object, or any other Zope object that is URL-accessible and which returns browser-renderable content. The content is typically HTML, but Zope doesn't care. You can spit out XML or text or whatever you like.

Building the Zope Zoo Website

In this section, we'll create a simple web site in instance space for the "Zope Zoo". As the Zoo webmaster, it is your job to make the web site easy to use and manage. Here are some things you'll need:

  • Zoo users must easily move around the site, just as if they were walking through a real Zoo.
  • All of your shared web layout tools, like a Cascading Style Sheet (CSS), must be in one easy to manage location.
  • You must provide a simple file library of various documents that describe the animals.
  • You need a site map so that users can quickly get an idea of the layout of the entire Zoo.
  • A Guest book must be created so that Zoo visitors can give you feedback and comments about your site.
  • A what's new section must be added to the guest book so that you can see any recent comments that have been added.

 

Navigating the Zoo

In order for your navigation system to work, you will need to create some basic site structure. We need to create some folders in your Zope system that represent the structure of your site. Let's use a zoo structure made out of Folders, as shown in the figure below.

Zoo folder structure.

Figure 5-1 Zoo folder structure.

 

You should create a top-level folder named ZopeZoo. Within the ZopeZoo folder, you should create three subfolders, Reptiles, Mammals and Fish. Within the Mammals folder, you should create a folder named Whales. Within the Reptiles folder, you should create two folders, Lizards and Snakes.

To navigate your site, users will visit the default view of the ZopeZoo folder (the "front page") and click on one of the top level folders to enter that particular part of the Zoo. They should also be able to use a very similar interface to keep going deeper into the site. For instance, if the user wishes to visit the "Mammals" section, the view of the Mammals section should have a similar interface to that of the Zoo itself. Also, the user should be able to back out of a section and go up to the parent section.

To provide navigation facilities, in the ZopeZoo folder, create a DTML Method named navigation:

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

 

When the method you just created is executed, it displays a list of links. Each link targets the default view of a subfolder. The list of subfolders displayed depends on the context in which the method is executed. For example, if the method is executed in the context of the "Mammals" folder, it will display a link to the default view of the Whales folder. If the method is executed in the context of the "ZopeZoo" folder, it will display links to the default views of the "Mammals", "Fish", and "Reptiles" folders. It's important to notice that this method can be used to display the contents of any folder, so we can use it for most of our "default" folder views. Furthermore, since we've placed this method in the ZopeZoo folder, each of the zoo subfolders will acquire and use it.

Now, you need to incorporate the navigation method into the site. Let's create two DTML methods. One will be used as a standard "header" for all pages within the site, the other a standard "footer". Do this by first creating a DTML Method named standard_html_header in the ZopeZoo folder. We will include the navigation links in the display of this method by referencing the navigation method via dtml-var:

        <html>        <head><title><dtml-var title></title>          <!-- Changed by: Peter Sabaini, 05-Jan-2004 --></head>        <body>        <dtml-var navigation>

 

Now create a DTML Method named standard_html_footer in your ZopeZoo folder and provide it with this content:

        </body>        </html>

 

We need to add a front page to the Zoo site and then we can view the site and verify that the navigation works correctly.

Adding a Front Page to the Zoo

In order to display our navigation and standard header and footer, we need a front page that serves as the welcome screen for Zoo visitors. In order to do so, create a DTML Method in the ZopeZoo folder named index_html with the following content:

        <dtml-var standard_html_header>          <h1>Welcome to the Zope Zoo</h1>          <p>Here you will find all kinds of cool animals.  You are in          the <b><dtml-var getId></b> section.</p>        <dtml-var standard_html_footer>

 

Take a look at how your site appears by clicking on the View tab of the ZopeZoo folder. The results of doing so are shown in the figure below.

Zope Zoo front page.

Figure 5-2 Zope Zoo front page.

 

Here you start to see how things come together. At the top of your main page you see a list of links to the various subsections. These links are created by the navigation method that is included by the standard_html_header method.

You can use the navigation links to travel through the various sections of the Zoo. Use this navigation interface to find the reptiles section.

Zope builds this page to display a folder by looking for the default folder view method ,index_html. It walks up the zoo site folder by folder until it finds the index_html method in the ZopeZoo folder. It then calls this method on the Reptiles folder. The index_html method calls the standard_html_header method which in turn calls the navigation method. Finally, the index_html method displays a welcome message and calls the standard_html_footer.

What if you want the reptile page to display something besides the welcome message? You can replace the index_html method in the reptile section with a more appropriate display method and still take advantage of the zoo header and footer including navigation.

In the Reptile folder create a DTML Method named index_html. Give it some content more appropriate to reptiles:

        <dtml-var standard_html_header>        <h1>The Reptile House</h1>        <p>Welcome to the Reptile House.</p>        <p>We are open from 6pm to midnight Monday through Friday.</p>        <dtml-var standard_html_footer>

 

Now take a look at the reptile page by going to the Reptile folder and clicking the View tab.

Since the index_html method in the Reptile folder includes the standard headers and footers, the reptile page still includes your navigation system.

Click on the Snakes link on the reptile page to see what the Snakes section looks like. The snakes page looks like the Reptiles page because the Snakes folder acquires its index_html display method from the Reptiles folder instead of from the ZopeZoo folder.

Improving Navigation

The navigation system for the zoo works pretty well, but it has one big problem. Once you go deeper into the site you need to use your browser's back button to go back. There are no navigation links to allow you to navigate up the folder hierarchy. Let's add a navigation link to allow you to go up the hierarchy. Change the navigation method in the ZopeZoo folder:

        <a href="..">Return to parent</a><br>        <ul>        <dtml-in expr="objectValues('Folder')">          <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a><br></li>        </dtml-in>        </ul>

 

Now view the ZopeZoo folder to see how this new link works, as shown in the figure below.

Improved zoo navigation controls.

Figure 5-3 Improved zoo navigation controls.

 

As you can see, the Return to parent link allows you to go back up from a section of the site to its parent. However, some problems remain; when you are at the top level of the site you still get a Return to parent link which leads nowhere. Let's fix this by changing the navigation method to hide the parent link when you're in the ZopeZoo folder:

        <dtml-if expr="id != 'ZopeZoo'">          <a href="..">Return to parent</a><br>        </dtml-if>        <ul>        <dtml-in expr="objectValues('Folder')">          <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a><br></li>        </dtml-in>        </ul>

 

Now the method tests to see if the current context object is named ZopeZoo and declines to display the "Return to parent" link if so. View the ZopeZoo folder to see the result.

There are still some things that could be improved about the navigation system. For example, it's pretty hard to tell what section of the Zoo you're in. You've changed the reptile section, but the rest of the site all looks pretty much the same with the exception of having different navigation links. It would be nice to have each page tell you what part of the Zoo you're in.

Let's change the navigation method once again to display where you are in the Zoo:

        <dtml-if expr="id != 'ZopeZoo'">          <h2><dtml-var title_or_id> Section</h2>          <a href="..">Return to parent</a><br>        </dtml-if>        <ul>        <dtml-in expr="objectValues('Folder')">          <li><a href="&dtml-absolute_url;"><dtml-var title_or_id></a><br></li>        </dtml-in>        </ul>

 

Now view the ZopeZoo folder again and navigate into the Reptiles section. Notice that within the Reptiles section, you see a header which says "Reptiles Section", as shown in the figure below.

Zoo page with section information.

Figure 5-4 Zoo page with section information.

 

Factoring out Style Sheets

Zoo pages are built by collections of methods that operate on folders. For example, the header method calls the navigation method to display navigation links on all pages. In addition to factoring out shared behavior such as navigation controls, you can use different Zope objects to factor out shared content.

Suppose you'd like to use CSS (Cascading Style Sheets ) to tailor the look and feel of the zoo site. One way to do this would be to include the CSS tags in the standard_html_header method. This way every page of the site would have the CSS information. This is a good way to reuse content, however, this is not a flexible solution since you may want a different look and feel in different parts of your site. Suppose you want the background of the snakes page to be green, while the rest of the site should have a white background. You'd have to override the standard_html_header in the Snakes folder and make it exactly the same as the normal header with the exception of the style information. This is an inflexible solution since you can't vary the CSS information without changing the entire header.

You can create a more flexible way to define CSS information by factoring it out into a separate object that the header will insert. Create a DTML Document in the ZopeZoo folder named style_sheet. Change the contents of the document to include some style information:

        <style type="text/css">        h1{          font-size: 24pt;          font-family: sans-serif;        }        p{          color: #220000;        }        body{          background: #FFFFDD;        }        </style>

 

This is a CSS style sheet that defines how to display h1, p and body HTML tags. Now let's include this content into our web site by inserting it into the standard_html_header method:

        <html>        <head>        <dtml-var style_sheet>        </head>        <body>        <dtml-var navigation>

 

Now, when you look at documents on your site, all of their paragraphs will be dark red, and the headers will be in a sans-serif font.

To change the style information in a part of the zoo site, just create a new style_sheet document and drop it into a folder. All the pages in that folder and its sub-folders will use the new style sheet.

Creating a File Library

File libraries are common on web sites since many sites distribute files of some sort. The old fashioned way to create a file library is to upload your files, then create a web page that contains links to those files. With Zope you can dynamically create links to files. When you upload, change or delete files, the file library's links can change automatically.

Create a folder in the ZopeZoo folder called Files. This folder contains all of the file you want to distribute to your web visitors.

In the Files folder create some empty file objects with names like DogGrooming or HomeScienceExperiments, just to give you some sample data to work with. Add some descriptive titles to these files.

DTML can help you save time maintaining this library. Create an index_html DTML Method in the Files folder to list all the files in the library:

        <dtml-var standard_html_header>        <h1>File Library</h1>        <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>  

 

Now view the Files folder. You should see a list of links to the files in the Files folder as shown in Figure 5-5.

File library contents page.

Figure 5-5 File library contents page.

 

If you add another file, Zope will dynamically adjust the file library page. You may also want to try changing the titles of the files, uploading new files, or deleting some of the files.

The file library as it stands is functional but Spartan. The library doesn't let you know when a file was created, and it doesn't let you sort the files in any way. Let's make the library a little fancier.

Most Zope objects have a bobobase_modification_time method that returns the time the object was last modified. We can use this method in the file library's index_html method:

        <dtml-var standard_html_header>        <h1>File Library</h1>        <table>          <tr>            <th>File</th>            <th>Last Modified</th>           </tr>        <dtml-in expr="objectValues('File')">          <tr>             <td><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></td>             <td><dtml-var bobobase_modification_time fmt="aCommon"></td>          </tr>        </dtml-in>        </table>        <dtml-var standard_html_footer>  

 

The new file library method uses an HTML table to display the files and their modification times.

Finally let's add the ability to sort this list by file name or by modification date. Change the index_html method again:

        <dtml-var standard_html_header>        <h1>File Library</h1>        <table>          <tr>            <th><a href="&dtml-URL0;?sort=name">File</a></th>            <th><a href="&dtml-URL0;?sort=date">Last Modified</a></th>           </tr>        <dtml-if expr="_.has_key('sort') and sort=='date'">          <dtml-in expr="objectValues('File')"                    sort="bobobase_modification_time" reverse>            <tr>               <td><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></td>               <td><dtml-var bobobase_modification_time fmt="aCommon"><td>            </tr>          </dtml-in>        <dtml-else>                <dtml-in expr="objectValues('File')" sort="id">            <tr>               <td><a href="&dtml-absolute_url;"><dtml-var title_or_id></a></td>               <td><dtml-var bobobase_modification_time fmt="aCommon"><td>            </tr>          </dtml-in>        </dtml-if>        </table>        <dtml-var standard_html_footer>  

 

Now view the file library and click on the File and Last Modified links to sort the files. This method works with two sorting loops. One uses the in tag to sort on an object's id. The other does a reverse sort on an object's bobobase_modification_time method. The index_html method decides which loop to use by looking for the sort variable. If there is a sort variable and if it has a value of date then the files are sorted by modification time. Otherwise the files are sorted by id.

Building a Guest Book

A guest book is a common and useful web application that allows visitors to your site to leave messages. Figure Figure 5-6 shows what the guest book you're going to write looks like.

Zoo guest book.

Figure 5-6 Zoo guest book.

 

Start by creating a folder called GuestBook in the root folder. Give this folder the title The Zope Zoo Guest Book. The GuestBook folder will hold the guest book entries and methods to view and add entries. The folder will hold everything the guest book needs. After the guest book is done you will be able to copy and paste it elsewhere in your site to create new guest books.

You can use Zope to create a guest book several ways, but for this example, you'll use one of the simplest. The GuestBook folder will hold a bunch of Files, one file for each guest book entry. When a new entry is added to the guest book, a new file is created in the GuestBook folder. To delete an unwanted entry, just go into the GuestBook folder and delete the unwanted file using the management interface.

Let's create a method that displays all of the entries. Call this method index_html so that it is the default view of the GuestBook folder:

        <dtml-var standard_html_header>        <h2><dtml-var title_or_id></h2>        <!-- Provide a link to add a new entry, this link goes to the        addEntryForm method -->        <p>          <a href="addEntryForm">Sign the guest book</a>        </p>        <!-- Iterate over each File in the folder starting with        the newest documents first. -->        <dtml-in expr="objectValues('File')"                 sort="bobobase_modification_time" reverse>        <!-- Display the date, author and contents of each file -->          <p>          <b>On <dtml-var bobobase_modification_time fmt="aCommon">,              <dtml-var guest_name html_quote null="Anonymous"> said:</b><br>          <dtml-var sequence-item html_quote newline_to_br>          <!-- Make sure we use html_quote so the users can't sneak any          HTML onto our page -->        </p>        </dtml-in>        <dtml-var standard_html_footer>

 

This method loops over all the files in the folder and displays each one. Notice that this method assumes that each file will have a guest_name property. If that property doesn't exist or is empty, then Zope will use Anonymous as the guest name. When you create a entry file you'll have to make sure to set this property.

Next, let's create a form that your site visitors will use to add new guest book entries. In the index_html method above we already created a link to this form. In your GuestBook folder create a new DTML Method named addEntryForm:

        <dtml-var standard_html_header>        <p>Type in your name and your comments and we'll add it to the        guest book.</p>        <form action="addEntryAction" method="POST">        <p> Your name:           <input type="text" name="guest_name" value="Anonymous">        </p>        <p> Your comments: <br>          <textarea name="comments" rows="10" cols="60"></textarea>        </p>        <p>          <input type="submit" value="Send Comments">        </p>          </form>        <dtml-var standard_html_footer>

 

Now when you click on the Sign Guest Book link on the guest book page you'll see a form allowing you to type in your comments. This form collects the user's name and comments and submits this information to a method named addEntryAction.

Now create an addEntryAction DTML Method in the GuestBook folder to handle the form. This form will create a new entry document and return a confirmation message:

        <dtml-var standard_html_header>        <dtml-call expr="addEntry(guest_name, comments)">        <h1>Thanks for signing our guest book!</h1>        <p><a href="<dtml-var URL1>">Return</a>        to the guest book.</p>        <dtml-var standard_html_footer>

 

This method creates a new entry by calling the addEntry method and returns a message letting the user know that their entry has been added.

The last remaining piece of the puzzle is to write the script that will create a file and sets its contents and properties. We'll do this in Python since it is much clearer than doing it in DTML. Create a Python-based Script in the GuestBook folder called addEntry with parameters guest_name and comments:

        ## Script (Python) "addEntry"        ##parameters=guest_name, comments        ##        """        Create a guest book entry.        """        # create a unique file id        id='entry_%d' % len(context.objectIds())        # create the file        context.manage_addProduct['OFSP'].manage_addFile(id,                                                 title="", file=comments)        # add a guest_name string property        doc=getattr(context, id)        doc.manage_addProperty('guest_name', guest_name, 'string')

 

This script uses Zope API calls to create a File and to create a property on it. This script performs the same sort of actions in a script that you could do manually; it creates a file, edits it and sets a property.

The guest book is now almost finished. To use the simple guest book, just visit http://localhost:8080/GuestBook/.

One final thing is needed to make the guest book complete. More than likely your security policy will not allow anonymous site visitors to create files. However the guest book application should be able to be used by anonymous visitors. In Chapter 7, User and Security, we'll explore this scenario more fully. The solution is to grant special permission to the addEntry method to allow it to do its work of creating a file. You can do this by setting the Proxy role of the script to Manager. This means that when the script runs it will work as though it was run by a manager regardless of who is actually running the method. To change the proxy roles go to the Proxy view of the addEntry script, as shown in Figure 5-7.

Setting proxy roles for the addEntry script.

Figure 5-7 Setting proxy roles for the addEntry script.

 

Now select Manager from the list of proxy roles and click Change.

Congratulations, you've just completed a functional web application. The guest book is complete and can be copied to different sites if you want.

Extending the Guest Book to Generate XML

All Zope objects can create XML. It's fairly easy to create XML with DTML. XML is just a way of describing information. The power of XML is that it lets you easily exchange information across the network. Here's a simple way that you could represent your guest book in XML:

        <guestbook>          <entry>            <comments>My comments</comments>          </entry>          <entry>            <comments>I like your web page</comments>          </entry>          <entry>            <comments>Please no blink tags</comments>          </entry>        </guestbook>

 

This XML document may not be that complex but it's easy to generate. Create a DTML Method named "entries.xml" in your guest book folder with the following contents:

        <guestbook>          <dtml-in expr="objectValues('DTML Document')">          <entry>            <comments><dtml-var document_src html_quote></comments>          </entry>          </dtml-in>        </guestbook>

 

As you can see, DTML is equally adept at creating XML as it is at creating HTML. Simply embed DTML tags among XML tags and you're set. The only tricky thing that you may wish to do is to set the content-type of the response to text/xml, which can be done with this DTML code:

        <dtml-call expr="RESPONSE.setHeader('content-type', 'text/xml')">

 

The whole point of generating XML is producing data in a format that can be understood by other systems. Therefore you will probably want to create XML in an existing format understood by the systems you want to communicate with. In the case of the guest book a reasonable format may be the RSS (Rich Site Summary) XML format. RSS is a format developed by Netscape for its my.netscape.com site, which has since gained popularity among other web logs and news sites. The Zope.org web site uses DTML to build a dynamic RSS document.

Congratulations! You've XML-enabled your guest book in just a couple minutes. Pat yourself on the back. If you want extra credit, research RSS enough to figure out how to change entries.xml to generate RSS.

The Next Step

This chapter shows how simple web applications can be made. Zope has many more features in addition to these, but these simple examples should get you started on create well managed, complex web sites.

In the next chapter, we'll see how the Zope security system lets Zope work with many different users at the same time and allows them to collaborate together on the same projects.