Deutsche Zope User Group
Gast 2 Benutzer online
DZUG-News

Zopebuch: Inhaltsverzeichnis 

Dieses Dokument ist momentan leider noch nicht vollst�ndig �bersetzt.

Kapitel 8: Variablen und DTML f�r Fortgeschrittene

DTML ist eine Sprache, die in der Regel "tut, was man meint". Das ist vor allem dann gut, wenn alles so l�uft, wie man es sich vorstellt. Ist das aber nicht der Fall, so ist dies eher eine schlechte Eigenschaft. Dieses Kapitel soll Ihnen zeigen, wie Sie DTML dazu bringen, das zu tun, was Sie wirklich meinen. DTML hat einen gewissen Ruf, sehr komplex zu sein, und zu einem Teil stimmt dies auch. DTML ist sehr einfach, wenn es um einfache Layout-Aufgaben geht, die wir bisher kennen gelernt haben. Will man allerdings DTML f�r komplexere Aufgaben benutzen, so m�ssen wir ein gutes Verst�ndnis der Herkunft von Variablen und deren Inhalten haben.

Nun folgt ein wirklich schwieriges Beispiel, �ber das fast alle "Neulinge" einmal stolpern. Stellen wir uns vor, wir haben ein DTML-Dokument namens zooName. Der Inhalt sieht aus wie folgt:

    

      

        

Sieht einfach aus, nicht? Diese DTML-Seite ruft sich selber auf, da die HTML-Aktion auf die URL Variable verweist, welches nat�rlich die URL des DTML Documentes ist.

Wenn nun also die zooName Variable existiert, wird unsere Seite diese ausgeben. Existiert die Variable hingegen nicht, so wird ein Formular angezeigt, in dem wir diese Variable eingeben k�nnen. Wenn wir auf "submit" klicken, wird der eingegebene Wert die "if"-Abfrage wahr machen, und der folgende Code sollte den eingegebenen Wert auf der Seite ausgeben.

Leider ist dies einer der F�lle, in dem DTML nicht das tut, was man m�chte, weil der Name des Dokuments ebenfalls zooName ist, und so wird nicht die Variable aus dem Request-Objekt benutzt, sondern das Dokument selbst, welches sich wiederum selber aufruft und so weiter, bis Zope mit einem "exessive Recursion" Fehler den L�ffel abgibt. In den folgenden Abschnitten soll gezeigt werden, wie sich dieser Fehler beseitigen l�sst und wie man DTML dazu bringt, das zu tun, was wir meinen.

Wie Variablen nachgesehen werden

Genau genommen gibt es zwei Wege, den Fehler im zooName Dokument zu beheben. Der erste besteht darin, das Dokument inzopeNameFormOrReply umzubenennen, sich f�r den Rest seiner Tage an diesen Sachverhalt zu erinnern und diesen Fehler niemals wieder zu machen, ohne zu wissen, was genu eigentlich der Fehler ist. Der zweite Weg besteht darin, sich dar�ber klar zu werden, wie Variablen und deren Werte in Zope gesucht und gefunden werden. Dann k�nnen wir Zope genau sagen, wo im Namensraum ("Namespace") wir den Namen der Variablen aufgel�st haben m�chten.

Der DTML-Namensraum gleicht einer Ansammlung von Objekten auf einem Stapel ("Stack"). Ein Stapel ist eine Liste von Objekten, die durch "Drauflegen" ("push") und "Herunternehmen" ("pop") von neuen oder vorhandenen Objekten ver�ndert werden kann. Zope erzeugt immer dann einen DTML-Namensraum, wenn DTML Dokumente oder -Methoden ausgef�hrt werden. Dieser Namensraum dient dann dazu, DTML-Variablennamen aufzul�sen.

Es ist sehr wichtig, die inneren Abl�ufe im Namensraum zu verstehen, damit sich akkurat voraussagen l�sst, auf welche Weise Zope unsere Variablen findet. Einige der schwierigsten DTML-Probleme lassen sich durch genaues Verst�ndnis des DTML-Namensraum l�sen.

Wenn Zope Variablennamen im DTML-Namensraum stack sucht, so schaut es zuerst auf das Objekt, welches "oben" auf dem Stapel liegt. Kann der Name dort nicht gefunden werden, so ist das n�chst tiefere Objekt auf dem Stack an der Reihe und so weiter. Auf diese Weise arbeitet sich Zope bis auf den "Boden" des Stapels vor und versucht, den Variablennamen aufzul�sen. Bleibt diese Suche erfolglos, so wird ein Fehler generiert und angezeigt.

Suchen wir nach einem nicht-existenten Namen, z. B. unicorn:

      

Gibt es keine Variable dieses Namens (unicorn), so erhalten wir bei Ansehen dieses Dokumentes den in Abbildung 7-1 gezeigten Fehler..

DTML Fehler �ber eine nicht gefundene Variable.

Abbildung 7-1 DTML Fehlermeldung �ber eine unbekannte Variable.

Der Namestack ist allerdings anf�nglich nicht einfach leer, sondern er enth�lt bereits vor der Ausf�hrung von DTML einige Objekte.

DTML-Namensr�ume

DTML-Namensr�ume werden dynamisch f�r jede Anforderung ("Request") erzeugt. Wird zum Beispiel eine DTML-Methode oder ein Dokument durch einen Web-Browser angefordert, enth�lt der DTML-Namensraum zwei Objekte: Das client- und das Request-Objekt, wie in Abbildung 7-2

Initialer DTML-Namensraum-Stack. gezeigt.

Abbildung 7-2 Initialer DTML-Namensraum-Stack.

Das client-Object liegt oben auf dem Namensraum-Stack. Um welches Objekt es sich handelt, h�ngt davon ab, ob wir ein DTML-Dokument oder eine -Methode betrachten. In unserem obigen Beispiel heisst das client-Objekt zooName. Dies ist auch der Grund f�r den Fehler. Die Formular-Variable kommt eigentlich aus dem Request-Objekt, aber das Client-Objekt wird zuerst gefunden, weil es oben auf dem Stack liegt./p>

Der Namensraum des request-Objektes kommt immer an letzter Stelle im DTML-Namensraum, daher wird dieses Objekt auch als letztes nach Variablennamen durchsucht. Dies bedeutet, dass wir genau spezifieren m�ssen, welchen Namensraum wir verwenden m�chten. Dies geschieht mit Hilfe des DTML-Tags with

      

        
          
            

In diesem Fall gibt der "with" tag an, dass im REQUEST-Namensraum und nur im REQUEST-Namensraum, nach "zooName" gesucht werden soll.

Das DTML-Client-Objekt

Das Client-Objekt h�ngt ebenfalls davon ab, ob wir eine Methode oder ein Dokument ausf�hren. Handelt es sich um ein Dokument, so ist das Client-Objekt immer das Dokument selbst; in anderen Worten, das Client-Objekt eines DTML-Dokumentes ist immer das Dokument selbst.

Eine DTML-Methode dagegen kann verschiedene Client-Objekte haben, je nachdem, auf welche Weise die Methode aufgerufen wird. Nehmen wir z. B. eine Methode, welche den Inhalt eines Ordners ("Folder") anzeigt; in diesem Fall ist das Client-Objekt der Ordner, dessen Inhalt durch die Methode angezeigt wird. Das Client-Objekt kann sich �ndern, je nachdem, welcher Folder angezeigt wird: Nehmen wir folgende TML Methode namens list im root-folder als Beispiel:

        

        

Was diese Methode anzeigt, h�ngt davon ab, auf welche Art sie ausgef�hrt wird. Wenden wir diese Methode auf den Reptiles Folder mit der URL http://localhost:8080/Reptiles/list an, so werden wir etwas �hnliches wie in Abbildung 7-3 erhalten..

Anwenden der List-Methode auf den Reptiles-folder.

Abbildung 7-3 Anwenden der list-Methode auf den "Reptiles" folder.

Wenden wir die list-Methode dagegen auf den Birds folder mit der URL http://localhost:8080/Birds/list an, werden wir ein anderes Ergebnis erhalten, n�mlich nur zwei Eintr�ge in der Liste: Parrot und Raptors.

Gleiche DTML-Methode, unterschiedliche Ergebnisse. Im ersten Beispiel wurde die list-Methode auf den Reptiles folder angewendet; im zweiten Beispiel war das Client-Objekt der Birds folder. Bei der Aufl�sung der objectValues Variable fand Zope also einmal die objectValues Methode des Reptiles Ordners, im zweiten Fall dagegen die objectValues Methode des Birds-Ordners.

In anderen Worten: Im client-Objekt wird zuerst nach Properties und Methoden-Namen gesucht.

Wie wir in Kapitel 4 "Dynamischer Inhalt mit DTML" gesehen haben, durchsucht Zope die Container eines Objektes, wenn es die Variable nicht im client-Objekt findet. Zope benutzt dazu die Akquisition, um automatisch die Variablen des Containers zu erben, der das client-Objekt enth�lt. Wenn Zope also auf der Suche nach Variablen die Objekthierarchie hochklettert, sucht es immer zuerst im Client-Objekt und arbeitet sich von dort nach oben.

Das DTML-Request-Objekt

Das Request-Objekt befindet sich ganz unten im DTML-Namensraum-Stack und enth�lt alle Informationen, die den aktuellen Web-Request betreffen.

Genau wie das Client Objekt nutzt auch das Request-Objekt Akquisition, um in mehreren Namensr�umen nach Variablen zu suchen. Im einzelnen sind dies die folgenden Objekte:

  1. Die CGI-Umgebung. Das Common Gateway Interface (auch kurz CGI genannt) definiert eine Standardumgebung f�r dynamische Web-Scripte und Applikationen. Diese Variablen werden von Zope im REQUEST-Namensraum abgelegt.
  2. Formular-Daten. Ist das aktuelle Objekt eine Form-Action (d.h. das Ziel eines &lquot;FORM>-Tags), so finden sich alle Eingabefelder des Formulars im REQUEST-Objekt wieder.
  3. Cookies. Hat der aktuelle Client Cookie-Daten gesetzt, so finden sich diese im aktuellen REQUEST Objekt.
  4. Weitere Variablen. Im REQUEST-Namensraum finden sich eine Menge weiterer n�tzlicher Variablen, so zum Beispiel die URL des aktuellen Objektes und auch die all seiner Parents.

Der Request-Namensraum ist in Zope sehr n�tzlich, da er die prim�re Art und Weise darstellt, �ber die Zope mit dem Client (in der Regel der Benutzer eines Webbrowsers Formulardaten, Cookies und andere Informationen �bermittelt.

Mehr Informationen �ber das Request-Objekt finden sich auch in Anhang B.

Wenn all diese Ausf�hrung sehr theoretisch erscheinen, ist es meist hilfreich, auf irgendeiner Seite einmal den folgenden DTML-Schnippsel einzuf�gen, welcher alle Daten des aktuellen Request-Objektes in lesbarer Form darstellt:

        

        

        

Die Ausgabe dieser Seite sollte in etwa Abbildung 7-4 entsprechen.

Das Request-Objekt.

Abbildung 7-4 Das Request-Objekt.

Da das Request-Objekt im Stack nach dem Client-Ojekt folgt, wird bei einer Variablen, die in beiden Namensr�umen existiert, das erste Vorkommen dieser Variablen aufgel�st, also im Client-Objekt. Dies kann zu einem Problem werden, und im folgenden wollen wir Wege aufzeigen, wie dieses Problem umgangen werden kann, indem wir mehr Einfluss auf die Art und Weise nehmen, in der DTML Variablennamen aufl�st. controlling more directly how DTML looks up variables.

Variablen darstellen ("Rendering")

Wird in Zope eine Variable �ber den var tag eingef�gt, so wird diese zun�chst im DTML-Namensraum aufgel�st, dann "dargestellt" ("gerendert") und das Resultat eingef�gt. "Rendern" bedeutet in diesem Fall die Transformation von einem Objekt in etwas, dass sich in der Ausgabe (in der Regel HTML, welches f�r einen Browser bestimmt ist) darstellen l�sst.

Zope rendert einfache Variablen, indem es sich der Standard-Python-Methode zur Transformation von Objekten in Zeichenketten ("Strings") bedient. F�r komplexere Objekte wie DTML- und SQL-Methoden ruft Zope das entsprechende Objekt auf und versucht nicht etwa, es einfach in einen String zu verwandeln. Dieser Mechanismus macht es sehr einfach, DTML-Methoden innerhalb von anderen DTML-Methoden zu verwenden und so komplexe Objekte zu erzeugen.

In der Regel rendert Zope Variablen so, wie "man es erwartet". Erst wenn wir fortgeschrittene Techniken verwenden, wird der eigentliche Rendering-Prozess deutlich. Sp�ter in diesem Kapitel werden wir einige Beispiele betrachten, wie sich das Rendering durch die DTML-Hilfsmethode getitem steuern l�sst.

Den DTML-Namensraum modifizieren

Jetzt, wo wir wissen, dass der DTML-Namensraum eine Stack-Struktur hat, fragen wir uns eventuell, warum das eigentlich so ist.

Einige DTML tags ver�ndern den DTML-Namensraum w�hrend ihrer Ausf�hrung. Ein Tag kann vielleicht ein neues Objekt auf den Stack legen wie z. B. das in tag, das with tag und auch das let tag.

In Namespace-Modifikationen durch DTML-Tags

W�hrend einer in Tag Iteration �ber eine Sequenz schiebt dieses das aktuelle Objekt, �ber welches gerade iteriert wird, oben auf den Namensraum-Stack:

  

        

           
        

Dieses Konstrukt ist uns bereits oft begegnet. W�hrend der Iteration des in tags �ber eine Sequenz wird jeded Item oben auf den Namensraum-Stack geschoben. Ist der Block beendet, wird das aktuelle Item aus dem Namensraum-Stack entfernt und das n�chste auf den Stack geschoben, bis die Sequenz abgearbeitet ist.

Das With Tag

Das with tag erm�glicht es, ein beliebiges, festgelegtes Objekt oben auf den Namensraum-Stack zu legen. Dies erm�glicht die genaue Definition des Objekts, in dem zuerst nach Variablen gesucht werden soll (f�r die gesamte Dauer des with-Blocks). Nach Beendigung des Blocks wird das Objekt aus dem Namensraum-Stack entfernt (jedenfalls on der "Spitze").

Denken wir uns einen Ordner, der diverse Methoden und Properties enth�lt, welche uns interessieren. Wir k�nnten den Inhalt z. B. mit Pyhon-Methoden wie im folgenden Beispiel ansprechen::

        

        
        

        
          
        

        

Wie man sieht, wird die Sache sehr komplex, obwohl wir nur den Inhalt des Reptiles Ordners ansprechen wollen.. Mit Hilfe des with Tags l�sst sich der Code stark vereinfachen:



        

          
          

          
            
          

        

        

Ein weiteres Anwendungsgebiet f�r den with Tag ist gegeben, wenn wir das Request-objekt (oder einen Teil dessen) oben auf die Spitze des Namensraum-Stacks bef�rdern m�chten. Nehmen wir als Beispiel ein HTML-Formular, welches ein Input-Feld mit dem Namen id benutzt. Versuchen wir wir nun, die id Variable so aufzul�sen:

 

werden wir nat�rlich nicht die id aus dem Formular erhalten, sondern die id client-Objekt-Id, da diese ganz oben auf dem Namensraum-Stack liegt. Eine L�sung besteht darin, den Namensraum des Request-Objekts nach oben auf den Stack zu bef�rdern (unter Verwendung des with tags:

  

Dieses Vorgehen stellt sicher, dass wir zuerst die "id" aus dem Formular erhalten. (Anhang B enth�t die komplette API-Beschreibung des Request-Objektes)

Das auf dem Stack zu oberst liegende Formular ist jedoch nutzlos, wenn wir es abschicken ohne das id-Feld gef�llt zu haben. DTML kann die id dort nicht finden. Deshalb sucht es als n�chstes im Client-Objekt danach, findet dort eine id und liefert sie uns. Sie ist jedoch die id des Client-Objekts. Der with Tag jedoch hat ein Attribut, welches es uns erm�glicht nur das gew�nschte Objekt in den Namensraum einzuf�gen:

        
          
            
          
            

The form didn't contain an "id" variable.

Durch die Verwendung des only Attributs k�nnen wir genau angeben, wo nach bestimmten Variablen gesucht werden soll.

Der Let Tag

Mit dem let-Tag kann ein neuer Namespace auf den Namespace-Stapel geschoben werden. Dieser Namespace wird durch die Tag-Attribute des let-Tags definiert:

        
          

's your .

Dies ergibt die Anzeige:

        Bob's your uncle.

Der let-Tag erf�llt �hnliche Aufgaben wie der with-Tag. Der Hauptvorteil des let-Tags liegt in der M�glichkeit der Definition mehrerer Variablen, die in einem Block genutzt werden k�nnen. Der let-Tag erzeugt eine oder mehrerere Variablen mit ihren Werten und schiebt ein Namespace-Objekt, welches diese Variablen enth�lt auf die Spitze des DTML-Namespace-Stapels. Im Allgemeinen ist der with-Tag n�tzlicher, um bereits existierende Objekte auf den Namespace-Stapel zu schieben, let-Tag dagegen ist besser geeignet um neue Variablen f�r einen Block zu definieren.

Mit hoher Wahrscheinlichkeit ist es besser Python oder Perl zu verwenden, wenn man komplexe DTML-Skripte schreibt, die neue Variablen ben�tigen. Fortgeschrittenes Skriptprogrammieren wird im Kapitel 10, "Zope-Scripting f�r Fortgschrittene" beschrieben.

Der DTML-Namespace ist eine komplexe Sache, und seine Komplexit�t ist im Laufe der Zeit gewachsen. Trotzdem ist es hilfreich zu verstehen, wo die Variablen herkommen. Es ist noch hilfreicher, wenn immer genau angegeben wird, wo nach einer Variablen gesucht wird. Mit dem with-Tag und dem let-Tag kann der Namespace so kontrolliert werden, da� immer am richtigen Ort nach der gesuchten Variablen geschaut wird.

DTML Namensraumfunktionen

Wie fast alles in Zope ist auch der DTML Namensraum ein Objekt, auf welches �ber das _ (Unterstrich) Objekt zugegriffen werden kann. Der _ Namensraum wird auch h�ufig als "der unterstrich Namensraum" bezeichnet.

Der unterstrich Namensraum stellt dem Programmierer f�r seine Arbeiten viele n�tzlich Funktionen zur Verf�gung. Einige wollen wir im Folgenden betrachten.

Nehmen wir einmal an, ein Name soll dreimal ausgegeben werden. Das kann mit dem in Tag realisiert werden. Aber wie bringt man dem in Tag bei, dass die Ausgabe genau dreimal erfolgen soll? Man muss einfach nur eine Sequenz aus drei Objekten �bergeben:

      

      
  • : Mein Name ist Bob.

Die _.range(3) Pythonfunktion wird eine Sequenz bestehend aus den ersten drei Integervariablen 0,1 und 2 zur�ckgeben. Die range Funktion ist standard Python built-in und kann genauso wie die meisten standard built-in Funktionen von Python �ber den _ Namensraum angesprochen werden. Das Funktioniert auch z.B. mit folgenden Funktionen:

range([start,], stop, [step])
Gibt eine Liste von Integern von start bis stop mit step Spr�ngen zurr�ck. Der Standardwert f�r start ist 0 und der Standardwert f�r step ist 1. Zum Beispiel gibt
        '_.range(3,9,2)' folgende Liste zur�ck: '[3,5,7,9]'.

        'len(sequenz)' -- 'len' Gibt die Anzahl der Werte die die Liste enth�lt zur�ck.

Viele dieser Ausdr�cke stammen aus der Programmiersprache Python, welche eine bestimmte Anzahl von speziellen Funktionen enth�lt, 'built-ins' genannt. Laut Python-Philosophie, soll es nur eine kleine Anzahl eingebauter Funktionen geben. Dagegen soll es nach der Zope-Philosophie eine gro�e Menge komplexer, eingebauter Funktionen geben.

Mit dem 'Unterstrich-Namensraum' kann die Suche nach einer Variablen gesteuert werden. Dies ist eine der h�ufigsten Anwendungen dieser Syntax. Sie haben gesehen, da� das 'in-Tag' eine Anzahl spezieller Variablen definiert, so z.B. sequence-item und sequence-key, die Sie innerhalb einer Schleife nutzen k�nnen, um sie anzuzeigen und zu steuern. Wie sieht es wohl aus, wenn Sie eine dieser Variablen innerhalb eines Python-Ausdrucks verwenden wollen?:

      

      

The squares of the first three integers:

  • The square of is:

Try this, does it work? No! Why not? The problem lies in this var tag:

      

Remember, everything inside a Python expression attribute must be a valid Python expression. In DTML, sequence-item is the name of a variable, but in Python this means "The object sequence minus the object item ". This is not what you want.

What you really want is to look up the variable sequence-item. One way to solve this problem is to use the in tag prefix attribute. For example:

      

      

The squares of the first three integers:

  • The square of is:

The prefix attribute causes in tag variables to be renamed using the specified prefix and underscores, rather than using "sequence" and dashes. So in this example, "sequence-item" becomes "loop_item". See Appendix A for more information on the prefix attribute.

Another way to look up the variable sequence-item in a DTML expression is to use the getitem utility function to explicitly look up a variable:

      The square of  is:
      

The getitem 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 getitem method takes an optional second argument which specifies whether or not to render the variable. Recall that rendering a DTML variable means turning it into a string. By default the getitem function does not render a variable.

Here's how to insert a rendered variable named myDoc:

      

This example is in some ways rather pointless, since it's the functional equivalent to:

      

However, suppose you had a form in which a user got to select which document they wanted to see from a list of choices. Suppose the form had an input named selectedDoc which contained the name of the document. You could then display the rendered document like so:

      

Notice in the above example that selectedDoc is not in quotes. We don't want to insert the variable named selectedDoc we want to insert the variable named by selectedDoc. For example, the value of selectedDoc might be chapterOne. Using indirect variable insertion you can insert the chapterOne variable. This way you can insert a variable whose name you don't know when you are authoring the DTML.

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 from DTML. This is explained more in Chapter 10, "Advanced Zope Scripting". Using Python sidesteps many of the issues in DTML.

DTML Security

Zope can be used by many different kinds of users. For example, the Zope site, Zope.org, has over 11,000 community members at the time of this writing. Each member can log into Zope, add objects and news items, and manage their own personal area.

Because DTML is a scripting language, it is very flexible about working with objects and their properties. If there were no security system that constrained DTML then a user could potentially create malicious or privacy-invading DTML code.

DTML is restricted by standard Zope security settings. So if you don't have permission to access an object by going to its URL you also don't have permission to access it via DTML. You can't use DTML to trick the Zope security system.

For example, suppose you have a DTML Document named Diary which is private. Anonymous users can't access your diary via the web. If an anonymous user views DTML that tries to access your diary they will be denied:

      

DTML 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 Unauthorized error and the user will be asked to present more privileged authentication credentials.

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.

Safe Scripting Limits

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 _.range utility function. You also have no way to access the filesystem directly in DTML.

Keep in mind however that these safety limits are simple and can be outsmarted by a determined user. It's generally not a good idea to let anyone you don't trust write DTML code on your site.

Advanced DTML Tags

In the rest of this chapter we'll look at the many advanced DTML tags. These tags are summarized in Appendix A. DTML has a set of built-in tags, as documented in this book, which can be counted on to be present in all Zope installations and perform the most common kinds of things. However, it is also possible to add new tags to a Zope installation. Instructions for doing this are provided at the Zope.org web site, along with an interesting set of contributed DTML tags.

This section covers what could be referred to as Zope miscellaneous tags. These tags don't really fit into any broad categories except for one group of tags, the exception handling DTML tags which are discussed at the end of this chapter.

The Call Tag

The var tag can call methods, but it also inserts the return value. Using the call tag you can call methods without inserting their return value into the output. This is useful if you are more interested in the effect of calling a method rather than its return value.

For example, when you want to change the value of a property, animalName, you are more interested in the effect of calling the manage_changeProperties method than the return value the method gives you. Here's an example:

      
        
        

The property 'animalName' has changed

No properties were changed

In this example, the page will change a property depending on whether a certain name exists. The result of the manage_changeProperties method is not important and does not need to be shown to the user.

Another common usage of the call tag is calling methods that affect client behavior, like the RESPONSE.redirect method. In this example, you make the client redirect to a different page, to change the page that gets redirected, change the value for the "target" variable defined in the let tag:

      

      

        

This page has moved, you will now be redirected to the correct location. If your browser does not redirect, click .

In short, the call tag works exactly like the var tag with the exception that it doesn't insert the results of calling the variable.

The Comment Tag

DTML can be documented with comments using the comment tag:

      

      

        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.

      

      

              

The comment block is removed from DTML output.

In addition to documenting DTML you can use the comment tag to temporarily comment out other DTML tags. Later you can remove the comment tags to re-enable the DTML.

The Tree Tag

The tree tag lets you easily build dynamic trees in HTML to display hierarchical data. A tree is a graphical representation of data that starts with a "root" object that has objects underneath it often referred to as "branches". Branches can have their own branches, just like a real tree. This concept should be familiar to anyone who has used a file manager program like Microsoft Windows Explorer to navigate a file system. And, in fact, the left hand "navigation" view of the Zope management interface is created using the tree tag.

For example here's a tree that represents a collection of folders and sub-folders.

HTML tree generated by the tree tag.

Abbildung 7-5 HTML tree generated by the tree tag.

Here's the DTML that generated this tree display:

      

      

        

      

      

The tree tag queries objects to find their sub-objects and takes care of displaying the results as a tree. The tree tag block works as a template to display nodes of the tree.

Now, since the basic protocol of the web, HTTP, is stateless, you need to somehow remember what state the tree is in every time you look at a page. To do this, Zope stores the state of the tree in a cookie. Because this tree state is stored in a cookie, only one tree can appear on a web page at a time, otherwise they will confusingly use the same cookie.

You can tailor the behavior of the tree tag quite a bit with tree tag attributes and special variables. Here is a sampling of tree tag attributes.

branches
The name of the method used to find sub-objects. This defaults to tpValues, which is a method defined by a number of standard Zope objects.
leaves
The name of a method used to display objects that do not have sub-object branches.
nowrap
Either 0 or 1. If 0, then branch text will wrap to fit in available space, otherwise, text may be truncated. The default value is 0.
sort
Sort branches before text insertion is performed. The attribute value is the name of the attribute that items should be sorted on.
assume_children
Either 0 or 1. If 1, then all objects are assumed to have sub-objects, and will therefore always have a plus sign in front of them when they are collapsed. Only when an item is expanded will sub-objects be looked for. This could be a good option when the retrieval of sub-objects is a costly process. The defalt value is 0.
single
Either 0 or 1. If 1, then only one branch of the tree can be expanded. Any expanded branches will collapse when a new branch is expanded. The default value is 0.
skip_unauthorized
Either 0 or 1. If 1, then no errors will be raised trying to display sub-objects for which the user does not have sufficient access. The protected sub-objects are not displayed. The default value is 0.

Suppose you want to use the tree tag to create a dynamic site map. You don't want every page to show up in the site map. Let's say that you put a property on folders and documents that you want to show up in the site map.

Let's first define a Script with the id of publicObjects that returns public objects:

      ## Script (Python) "publicObjects"
      ##
      """
      Returns sub-folders and DTML documents that have a
      true 'siteMap' property.
      """
      results=[]
      for object in context.objectValues(['Folder', 'DTML Document']):
          if object.hasProperty('siteMap') and object.siteMap:
              results.append(object)
      return results

Now we can create a DTML Method that uses the tree tag and our Scripts to draw a site map:

      

      

Site Map

Expand All | Collapse All

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.

Dynamic site map using the tree tag.

Abbildung 7-6 Dynamic site map using the tree tag.

For a summary of the tree tag arguments and special variables see Appendix A.

Der return Tag

Meist wird DTML verwendet, um eine Textausgabe zu erzeugen. Es ist jedoch genauso m�glich DTML beliebige Python Werte erzeugen zu lassen - genauso wie es z.B. Python Scripts machen.

Hier ein Beispiel:

      

This text is ignored.

Diese DTML Methode liefert die Zahl 42 zur�ck.

Ein Nebeneffekt des return Tag ist, dass die Ausf�hrung des DTML Codes nach durch diesen Tag beendet wird - schliesslich ist der R�ckgabewert jetzt ja gefunden.

Vor der Verwendung dieses Tags sollten Sie sich jedoch fragen, ob Sie nicht besser ein Python oder Perl Script verwenden. Er wurde entwickelt bevor es diese Alternative gab, und ist inzwischen �berholt. Logik wird besser in Skripten als in DTML ausgedr�ckt.

Der Sendmail Tag

Der sendmail Tag entwirft und sendet E-Mails. Zum Versand benutzt er ein existierendes Mail Host Objekt, optional kann auch ein bestimmter Mail Host angegeben werden.

Hier ein Beispiel:

  
      To: 
      Subject: Make Money Fast!!!!

      Take advantage of our exciting offer now! Using our exclusive method
      you can build unimaginable wealth very quickly. Act now!
  

Denken Sie daran, eine Leerzeile zwischen den Headern und dem Text der Nachricht einzuf�gen.

H�ufig wird der sendmail Tag dazu verwendet, um nach dem Ausf�llen eines Feedback Formulars eine Email an die Interessierten zu senden. Da der sendmail Tag beliebige andere DTML Tags enthalten kann, ist es leicht, ein E-Mail Template zu erstellen und es mit den Formulardaten zu f�llen.

The Mime Tag

The mime tag allows you to format data using MIME (Multipurpose Internet Mail Extensions). MIME is an Internet standard for encoding data in email message. Using the mime tag you can use Zope to send emails with attachments.

Suppose you'd like to upload your resume to Zope and then have Zope email this file to a list of potential employers.

Here's the upload form:

      

      

Send you resume to potential employers

Resume file:

Send to:

Yahoo
Microsoft
McDonalds

Create another DTML Method called sendresume to process the form and send the resume file:

      

      

         

          
          To: 
          Subject: Resume
          

          Hi, please take a look at my resume.

          
          

        

        

Your resume was sent.

You didn't select any recipients.

This method iterates over the sendto variable and sends one email for each item.

Notice that there is no blank line between the To: header and the starting mime tag. If a blank line is inserted between them then the message will not be interpreted as a multipart message by the receiving mail reader.

Also notice that there is no newline between the boundary tag and the var tag, or the end of the var tag and the closing mime tag. This is important, if you break the tags up with newlines then they will be encoded and included in the MIME part, which is probably not what you're after.

As per the MIME spec, mime tags may be nested within mime tags arbitrarily.

Der Unless Tag

Der unless Tag f�hrt den eingeschlossenen Code aus, wenn eine angegebenen Bedingung *nicht* zutrifft. Er ist damit das Gegenteil des if Tags. Folgender DTML Code:

 
     
        Es ist wirklich keine Butter!
      

bewirkt das Gleiche wie:

      
        Es ist wirklich keine Butter!
      

Was ist dann �berhaupt der Zweck des unless Tag? Er dient einfach nur der Bequemlichkeit. Auch ist er weniger ausdrucksstark als der if Tag, denn ihm kann kein else oder elif Tag folgen.

Genauso wie der if Tag, bewirkt die Verwendung des unless Tag mit dem name Attribut die �berpr�fung auf Existenz:

 
        The Easter Bunny does not exist or is not true.
      

�berpr�ft, ob the_easter_bunny existiert und ob es wahr ist. Folgendes Beispiel hingegen benutzt das expr Attribut und pr�ft daher ausschliesslich, ob das Objekt wahr ist:

 
        The Easter Bunny is not true.
      

Daher wird eine Ausnahme gemeldet, wenn the_easter_bunny nicht existiert.

Jeder unless Tags kann durch einen �quivalenten if Tag ersetzt werden, der dann die inverse Bedingung angibt. Seine Verwendung ist daher optional und eine Frage des Stils.

Batch Verarbeitung mit dem In Tag

H�ufig m�ssen Nutzern Listen von Eintr�gen wie z.B. Suchresultaten oder Ergebnissen einer Datenbankabfrage pr�sentiert werden. Werden diese Listen zu umfangreich, ist es nicht praktikabel diese alle auf einer Seite aufzulisten. Stattdessen ist eine Aufteilung der Liste in mehrere kleinere Listen w�nschenswert. So wird dies z.B. von Suchmaschinen gehandhabt, um dem Nutzer eine Vielzahl von Suchresultaten etappenweise anzeigen k�nnen.

Dieser Prozess wird im Englischen mit "batching" bezeichnet. In Ermangelung einer angemessenen �bersetzung wird dieser Begriff �bernommen.

Batching hat folgende Vorteile:

  • Die geringere Gr��e eines Batches verringert die Ladezeit eines Dokumentes.
  • Zope ben�tigt weniger Speicher
  • Navigationshilfen erleichtern die Orientierung innerhalb gro�er Listen.

Der in Tag stellt mehrere Variablen zur Verf�gung, um Batching zu erm�glichen. Schauen wir uns ein Beispiel an, dass zeigt, wie 100 Eintr�ge in Batches von 10 am St�ck angezeigt werden:

      

        

          

            
              
                 (Vorherige  Resultate)
              
            

            

Dies wird �ber dem Batch angezeigt:

  • Iteration number:
  • Dies wird unter dem Batch angezeigt.

    (N�chste Resultate)

    Was genau geht hier vor? Zuerst ist da ein in Tag, der �ber 100 Nummern iteriert, die von der range Funktion erzeugt werden. Das size Attribute l�sst den in Tag nur 10 Nummern auf einmal anzeigen. Das start Attribute gibt an, an welcher Stelle innerhalb der Liste der Batch beginnt.

    Der in Tags hat zwei if Tags als direkte Kindelemente. Der erste �berpr�ft die Variable sequence-start. Diese ist nur bei dem ersten Durchlauf des in Blocks wahr. Daher wird der Inhalt des Tags nur einmal am Anfang der Schleife ausgef�hrt. Der zweite if Tag �berpr�ft die Variable sequence-end. Diese wiederum ist nur beim letzten Durchlauf des in Blocks wahr. Entsprechend wird dieser if Block nur einmal am Ende der Schleife ausgef�hrt. Nur der Teil zwischen den beiden if Tags wird bei jedem Schleifendurchlauf ausgef�hrt.

    Innerhalb von beiden if Tags befindet sich ein weiterer if Tag der die Variablen previous-sequence bzw. next-sequence �berpr�ft. Diese Variablen sind wahr, wenn der aktuelle Batch einen Vorg�nger bzw. einen Folgebatch hat. previous-sequence ist also f�r alle Batches bis auf den ersten wahr, und next-sequence f�r alle bis auf den letzten. Wenn wahr, so wird ein Link zum Vorg�nger- oder Nachfolgebatch erzeugt.

    Diese Links referenzieren das eigene DTML Dokument, nur der query_start Query Parameter wird auf den Wert gesetzt, an dem der verlinkte Batch starten soll. Um ein Gef�hl daf�r zu bekommen, wie das funktioniert, sollte man diese Art der Navigation einmal benutzen und darauf achten, wie sich die URL dieser Navigationslinks in Abh�ngigkeit von der Position des Batches innerhalb der Gesamtliste �ndert.

    Schlie�lich werden in unserem Beispiel noch einige Kennzahlen der Batches mit Hilfe der next-sequence-size und previous-sequence-size Variablen ausgegeben. Diese ganze Logik gibt schlie�lich folgenden HTML Code aus:

          Zope
    
            

    Dies wird �ber dem Batch angezeigt:

    • Iteration number: 0
    • Iteration number: 1
    • Iteration number: 2
    • Iteration number: 3
    • Iteration number: 4
    • Iteration number: 5
    • Iteration number: 6
    • Iteration number: 7
    • Iteration number: 8
    • Iteration number: 9

    Dies wird unter dem Batch angezeigt.

    (N�chste 10 Resultate)

    Batch Verarbeitung kann sehr komplex sein. Eine gute Methode mit Batches zu arbeiten, ist die Benutzung des Searchable Interface Objektes, um eine Batch Ausgabe zu erhalten. Dieses DTML kann dann f�r die eigenen Bed�rfnisse angepasst werden. Dies wird n�her in Kapitel 11 "Inhalt durchsuchen und kategorisieren" beschrieben.

    Tags f�r die Behandlung von Ausnahmen

    Zope hat ausgefeilte Mechanismen zur Behandlung von Ausnahmen. Auf diese kann von DTML aus mit den raise und try Tags zugegriffen werden. Mehr �ber Ausnahmen und wie sie ausgel�st und behandelt werden, erfahren Sie in einf�hrenden B�chern �ber Python oder auch online im Python Tutorial.

    Der Raise Tag

    Mit dem raise Tag k�nnen Ausnahmen ausgel�st werden, um Fehler zu signalisieren. Es k�nnte zum Beispiel mit dem if Tag auf einen Fehler gepr�ft werden, um diesen dann mit dem raise Tag bekannt zu machen.

    Das type Attribut des raise Tags spezifiziert die Art des Fehlers. Dies ist ein kurzer beschreibender Name. Es gibt einige standardisierte Fehlernamen, z.B. Unauthorized und Redirect, welche eine HTTP Antwort mit einer Fehlernummer verursachen. Unauthorized Fehler f�hren dazu, dass der Browser einen Login Prompt anzeigt. Auch k�nnen HTTP Fehlernummern im type Attribut verwendet werden, die Zope in der HTTP Antwort verwendet. Zum Beispiel:

            Nicht gefunden

    Dies verursacht das Setzen des HTTP 404 (Not Found) Fehler in der HTTP Anwort an den Browser.

    Der raise Tag ist ein Block Tag. Der eingeschlossene Text bestimmt die Art der Fehlermeldung. Enth�lt er HTML Elemente, so wird er als Fehlermeldung gesendet, andererseits wird eine generische Fehlerseite erzeugt innerhalb derer der Text als Fehlerwert angezeigt wird.

    Hier ein Beispiel f�r den raise Tag:

            
    
              
    
              

    Euro wurden von Ihrem Konto abgebucht.

    Sie haben nicht gen�gend Geld auf Ihrem Konto .

    Ein wichtiger Seiteneffekt beim Ausl�sen von Ausnahmen ist der Rollback der aktuellen Transaktion. Das hei�t, dass alle �nderungen, die durch die aktuelle Anfrage ausgel�st wurden, zur�ckgenommen werden. Neben der M�glichkeit dem Nutzer eine Fehlermeldung anzuzeigen, erlauben es Ausnahmen also, beim Auftreten von Problemen evtl. bereits vorgenommene �nderungen r�ckg�ngig zu machen.

    Der Try Tag

    Wird eine Ausnahme entweder manuell mit dem raise Tag oder intern durch Zope ausgel�st, so kann diese mit dem try Tag abgefangen werden.

    Ausnahmen sind unerwartete Fehler, die w�hrend der Ausf�hrung von DTML Code entstehen. Wird eine Ausnahme entdeckt, stoppt Zope die weitere Ausf�hrung. Sehen Sie sich dazu folgendes Beispiel an:

            Kosten pro St�ck: 
                 
    

    Dieser DTML Code funktioniert tadellos solange total_units nicht Null ist. Ist dies jedoch der Fall, zeigt eine ZeroDivisionError Ausnahme diese ung�ltige Operation an. Anstelle der erwarteten Ausgabe wird jetzt eine Fehlermeldung angezeigt.

    Der try Tag kann benutzt werden, um dies zu verhindern. Mit ihm kann die Fehlerbehandlung in die eigene Hand genommen werden.

    Der try Tag hat zwei Funktionen. Erstens kann er die Ausgabe einer Fehlermeldung verhindern. Im Falle einer Ausnahme kann eingeschlossener Code auf den Fehler reagieren. Zweitens verhindert er den Abbruch der Ausf�hrung des DTML Codes.

    Innerhalb des try Tags gibt es einen oder mehrere except Tags die auf jeweils unterschiedliche Ausnahmen reagieren. Wird eine Ausnahme ausgel�st, so wird jeder except Tag auf seine Zust�ndigkeit f�r die Ausnahme hin �berpr�ft. Der erste gefundene except Tag behandelt die Ausnahme. Wird in einem except Tag kein spezifischer Ausnahmetyp angegeben, so ist er f�r alle Ausnahmen zust�ndig.

    Folgenderma�en m�sste der try Tag verwendet werden, um die Ausgabe einer Fehlermeldung im vorangehenden Beispiel zu vermeiden:

            
                  Kosten pro St�ck: 
                      
    
             
    
                  Kosten pro St�ck: N/A 
    
            
    

    Wird ein ZeroDivisionError ausgel�st, geht die Kontrolle auf den except Tag �ber, und "Kosten pro St�ck: N/A" wird ausgegeben. Nach der Ausf�hrung des except Blocks wird die Ausf�hrung des DTML Codes nach dem try Block wieder aufgenommen.

    DTML's except Tags funktionieren mit Python's klassenbasierten Ausnahmen. Wie in Python werden dabei auch Unterklassen der spezifizierten Ausnahmeklassen behandelt. Wird z.B. ArithmeticError in einem except Tag angegeben, so werden von diesem sowohl Ausnahmen der Klasse ArithmeticError als auch Ausnahmen von dessen Unterklassen, z.B. auch ZeroDivisionError behandelt. Eine Auflistung aller Ausnahmen der Python Standardbibliothek und ihrer Vererbungshierarchie findet sich z.B. in der Python Library Reference. Auch kann ein except Tag mehrere Ausnahmen spezifizieren und behandeln.

    Innerhalb eines except Tags kann auf Informationen �ber die behandelte Ausnahme �ber verschiedene durch Zope bereitgestellte Variablen zugegriffen werden.

    error_type
    Der Typ der behandelten Ausnahme.
    error_value
    Der Wert der Ausnahme.
    error_tb
    Der Traceback der behandelten Ausnahem.

    Diese Variablen k�nnen benutzt werden, um Fehlermeldungen f�r Nutzer zu erzeugen oder in Abh�ngigkeit von ihrem Wert - z.B. dem Fehlertyp - entweder dem Webmaster eine Email zu senden oder den Fehler zu loggen.

    Der optionale Else Block

    Im Anschluss an den try Tag kann ein else Block verwendet werden, der ausgef�hrt wird, wenn keine Ausnahme ausgel�st wurde. Hier ein Beispiel, das zeigt, wieso das sinnvoll sein kann:

               
    
                
    
              
    
                

    Wir haben nicht genug Futter!

    Die Krokos sind noch nicht hungrig.

    F�tterungsversuch nicht erfolgreich.

    Error type:

    Error value:

    Die Krokodile sind gef�ttert worden!

    Der erste except Block der f�r den auftretenden Fehler zust�ndig ist, wird ausgef�hrt. Wenn ein except Block keinen Namen hat, kann er alle Ausnahmen behandeln. Der optionale else Block wird ausgef�hrt, wenn keine Ausnahme innerhalb des try Blocks auftritt. Ausnahmen innerhalb des else Block werden nicht von den vorangehenden except Blocks behandelt.

    Der optionale Finally Block

    Der try Tag kann auch noch auf eine etwas andere Weise verwendet werden. Anstatt Ausnahmen zu behandeln, kann er benutzt werden, um nach ihrem Auftreten &aufzur�umen&.

    Der finally Tag innerhalb des try Tags enth�lt dazu Code, der immer ausgef�hrt wird, selbst wenn eine unbehandelte Ausnahme auftritt.

    Der finally Block ist dann n�tzlich, wenn sichergestellt werden muss, dass Code ausgef�hrt wird, egal ob eine Ausnahme auftritt oder nicht. Selbst wenn vorher ein return Tag wurde wird der finally Block ausgef�hrt. In diesem Fall wird jedoch jegliche Ausgabe des finally Blocks verworfen. Hier ein Beispiel daf�r wann der finally Tag n�tzlich sein k�nnte:

                
              
                  
              
                  
                  
              

    In diesem Beispiel wird die Sperrung einer Ressource erlangt, mit der gearbeitet werden soll. Wird eine Ausnahme bei ihrer darauffolgenden Verwendung ausgel�st, wird diese zwar nicht behandelt, aber es wird sichergestellt, dass die Sperrung wieder aufgehoben wird. Auch wenn keine Ausnahme auftritt, wird der finally Block ausgef�hrt und die Sperrung nach Abarbeitung des try Blocks aufgehoben.

    Der finally Tag wird in Zope selten verwendet, da solch komplizierte Programmabl�ufe besser in Skripten realisiert werden.

    Zusammenfassung

    DTML stellt umfangreiche Funktionalit�t zur Entwicklung von Webanwendungen zur Verf�gung. Wir haben uns in diesem Kapitel einige der m�chtigeren DTML Tags und ihre Optionen angeschaut. Eine vollst�ndigere Referenz zu DTML findet sich in Anhang A.

    Das n�chste Kapitel zeigt Ihnen, wie Sie Experte f�r Page Templates werden. W�hrend DTML ein ausdrucksstarkes Allzweckwerkzeug ist, sind Page Templates ein eleganterer Ansatz zur Erzeugung von HTML und anderen Markupsprachen.