Creating XML Applications With Zope
December 15, 1999
Zope is an open source application server that enables you to rapidly develop applications for the Web. Zope's unique object-oriented flavor make it an interesting choice for developing XML applications: Firstly, it allows you to treat XML content as objects. Then it allows you to write applications by creating methods for your XML objects.
At the most basic level, Zope provides an object database and a web ORB (Object Request Broker) to store XML and publish it on the Web. In addition, Zope gives you a menu of services to use when developing your XML data into an application. You can edit XML through the Web, index and search XML elements, manipulate XML with standard DOM methods, add dynamic behavior to XML elements with web-editable methods, control access to XML via a sophisticated security model, and more. Since Zope treats XML as normal Zope objects rather than plain data, you can quickly breathe life into your XML.
Getting Started with Zope
In this article we are going to look at the process of using Zope to develop a small web application centered around XML. We will build an FAQ viewer that stores its data in XML and allows browsing and searching. This article assumes that you have Zope installed and that you have some experience with Zope. If you aren't familiar with Zope, you may wish to consult the Zope Content Manager's Guide or Brian Lloyd's An Introduction to Zope. You can download Zope from Zope.org.
Getting XML into Zope
To get your XML into Zope, you need to use the free "XML Document" Zope product. You can download it from Zope.org (make sure you have version 1.0a3 or newer). To install the product, untar and unzip it inside your Zope directory (WinZip will do this if you run Windows). After restarting Zope, you should be able to create new XML Documents.
Create a new XML Document by selecting "XML Document" from the product add list. Give it an Id of "FAQ" and then click "Add and Edit". Now you should be at the XML Document editing screen. Here you can edit the content of your XML Document. Enter this XML:
<?xml version="1.0"?> <faq title="A Sample FAQ"> <entry> <question>To be or not to be?</question> <answer>That is the question.</answer> </entry> <entry> <question>The question of life the universe and everything?</question> <answer>42</answer> </entry> </faq>
Now click "Change". Zope will complain if your XML is not well formed. Note that Zope does not perform validation against a Document Type Definition (DTD) file. If you make a mistake you can undo your changes by clicking on the "Undo" tab. You can also upload an XML file into Zope by clicking on the "Upload" tab.
Advantages of Storing XML in Zope
Congratulations—you now have stored your XML in Zope's object database, making it publishable and editable through the web. As a bonus, changes you make to your XML are now "undoable," and you can edit your XML files via WebDAV and FTP. Storing your XML in an object database has allowed you to maximize access speed while keeping a lid on memory usage. Now you can control access to your XML, delegating editing and viewing privileges to other users. Plus you've bought free support from a dynamic open source community.
Another interesting thing about storing XML in Zope is that all the elements of your XML document are made accessible through the Web as true Zope objects. This means that every element in your XML document has a URL; can be called through the Web; and can call methods that access Zope services, such as accessing a RDBMS or sending mail.
Displaying XML
Zope uses a simple templating system with a tag-based scripting language to display objects. See the Z Document Template Markup Language Reference for more information about the Zope template scripting language. Zope templates act as methods that display the Zope objects. In the case of displaying XML, you will create "DTML Methods" which can be bound to individual XML elements in order to display them.
Viewing an "entry" Element
Let's create a template to view our FAQ entries. Create a new DTML Method by selecting "DTML Method" from the product add list, enter "viewEntry" as its Id, and give it this content:
<dtml-var standard_html_header> <h2>Q</h2> <p><dtml-var "text_content('question')"></p> <h2>A</h2> <p><dtml-var "text_content('answer')"></p> <dtml-var standard_html_footer>
Given an XML "entry" element like this:
<entry> <question>To be or not to be?</question> <answer>That is the question.</answer> </entry>
The template will return this HTML:
<HTML><BODY BGCOLOR="#FFFFFF"> <h2>Q</h2> <p>To be or not to be?</p> <h2>A</h2> <p>That is the question.</p> </BODY></HTML>
How does this template work? It consists of HTML interspersed with DTML tags that call methods on the XML element linked to the template. The important work is done by the "text_content" method, which returns text contained by an XML element. So, for example, the "<dtml-var text_content('question')>" tag inserts the text of the contained "question" XML element.
Displaying an Element with a Template
Let's test our "viewEntry" template by actually calling it through the Web on an "entry" element. The first step is to find the URL of an "entry" element. All Zope objects have URLs. An object's URL is visible at the top of the management screen when editing it.
Traverse to an individual "entry" element by expanding your XML Document in the left management frame and clicking on sub-objects. If you cannot expand your XML Document, click the "Refresh" link in the left management frame.
Here is what you should see when you successfully navigate to an individual "entry" element.
As you can see, the path part of the URL for this element is "/Sample/FAQ/e95/e98". To call a method on a Zope object, simply visit the URL of the object with the method name appended to the URL. For example, to call our "viewEntry" template on this "entry" element, you would point your browser at this URL: "/Sample/FAQ/e95/e98/viewEntry". Voila, you've just formatted and published XML with Zope! This process can be easily extended to allow you to call almost any method on any XML element.
Creating a Table of Contents
It would be useful to provide a table of contents for the entire FAQ. In this case the template will operate on the "faq" element. Create a DTML Template with Id "toc". Enter this content:
<dtml-var standard_html_header> <h2><dtml-var "getAttribute('title')"></h2> <dtml-in "getElementsByTagName('entry')"> <p><a href="<dtml-var absolute_url>/viewEntry"> <dtml-var "text_content('question')"></a></p> </dtml-in> <dtml-var standard_html_footer>
This template returns this HTML when used to display our "faq" element:
<HTML><BODY BGCOLOR="#FFFFFF"> <h2>A Sample FAQ</h2> <p><a href="http://localhost:8080/Sample/FAQ/e95/e98/viewEntry"> To be or not to be?</a></p> <p><a href="http://localhost:8080/Sample/FAQ/e95/e111/viewEntry"> The question of life the universe and everything?</a></p> </BODY></HTML>
This template first displays the title of the FAQ by calling a DOM method to get the "title" attribute of the "faq" element. Then it loops through the contained "entry" elements and creates a link for each one by calling its "absolute_url" method. Notice how this template automatically builds URLs to call methods in the same way you previously manually constructed a URL to call a method.
DTML templates can get complex. Nevertheless, at the heart of the process stand these simple ideas: templates can display individual XML elements, and templates work like methods that can be called through the Web.
Searching XML
Zope provides built-in indexing and searching tools that allow you to index and search all kinds of Zope objects, including XML elements. To index Zope objects, you simply create a ZCatalog object and configure its indexes. Zope searches using high performance indexes so it operates very quickly, even with large amounts of indexed data.
Configuring a ZCatalog
Create a ZCatalog by choosing "ZCatalog" from the product add list. Give the ZCatalog an Id of "Catalog". Then click on the catalog to manage it. Next choose the "Indexes" tab. From here you will be able to configure the search indexes. Check the boxes next to all the existing indexes and then click "Delete". This gets rid of the default indexes. Now create a new TextIndex named "document_src". This creates a full text index that is populated by calling the "document_src" method on Zope objects.
Now index our FAQ entries by choosing the "Find Items to ZCatalog" tab. Here we can locate objects to be indexed. In the "expr" field enter:
getNodeName()=='entry'
then click "Find". This tells Zope to look for objects that have a nodeName of "entry". You should now see that the ZCatalog has found and indexed our two FAQ entry objects.
Your XML is now indexed and ready to be searched.
Searching the ZCatalog
To search for FAQ entries we need to create search and results forms. Create two DTML Documents, one called "search" and the other called "results". The "search" document just consists of an HTML form whose action is the "results" document.
<dtml-var standard_html_header> <h2>Search</h2> <p> <form action="results"> <input type="text" name="document_src"> <input type="submit" value=" Search "> </form> </p> <dtml-var standard_html_footer>
The "results" document calls the ZCatalog and implicitly passes the search form data. It then iterates through the results of this search call and creates a link to each matched object:
<dtml-var standard_html_header> <h2>Search Results</h2> <dtml-in Catalog> <dtml-with "Catalog.getobject(data_record_id_)"> <p> <a href="<dtml-var absolute_url>/viewEntry"> <dtml-var "text_content('question')"> </a> </p> </dtml-with> </dtml-in> <dtml-var standard_html_footer>
View the search form, type a search term like "universe" into the search box, and click the "search" button. Now you should see the results of your search. You've successfully built a full text XML search engine!
Understanding the details of these forms is not essential: Zope comes with a wizard that helps you build search forms. The important part to grasp is that the ZCatalog object indexes Zope objects, including XML elements, and that simple HTML forms can be used to search over the indexed objects. Zope can index many heterogeneous types of objects and perform smart searches—such as locating all XML elements with an "author" attribute value of "Jim" that have been modified within the last week.
Putting It All Together
The complete working FAQ example is available for download here: Sample.zexp. The complete example includes a number of minor improvements over what we have examined in this article. You can take it apart and put it back together to find out how it works. To add the example into Zope, place the Sample.zexp file in the "import" directory of your Zope distribution (make the directory if it does not exist already) and then select the "Import/Export" tab from the folder where you want to place the example. Enter "Sample.zexp" as the Import file name, and click the "Import" button.
Where To Go From Here
This example only scratches the surface of what you can do with XML in Zope. For starters you might want to expand this example to handle DocBook's FAQ format, which provides a fuller FAQ model and a documented DTD. You can also use Zope to allow users to edit FAQ entries with web forms rather than editing the XML manually (plus you can decide how you want to delegate control). You can even allow remote FAQ management via XML-RPC. You might want to create alternate templates to allow for things like displaying the FAQ in plain text for download via FTP. Or you could add the ability to display and search the FAQ based on the last modified time of FAQ entries. Thankfully, whichever avenues you choose, you're never locked into a given solution since your data is always available in plain XML!