Zope-Seitenvorlagen für Fortgeschrittene

  • Send this page to somebody
  • Print this page
Fortgeschrittene ZPT-Techniken (9. Kapitel des Zopebuchs, Version Zope 2.5). Originalübersetzung von Gabriele Zöttl.

Original Zopebuch: Advanced Page Templates (2.6 Edition)

Kapitel 9: Zope-Seitenvorlagen für Fortgeschrittene

In Kapitel 5, "Zope-Seitenvorlagen verwenden", haben Sie die grundlegenden Merkmale von Seitenvorlagen kennen gelernt. Dieses Kapitel behandelt komplexere Verfahren, darunter auch neue Arten von Ausdrücken und Makros.

TAL für Fortgeschrittene

Sie haben bereits einiges über TAL-Anweisungen (Template Attribute Language: Auszeichnungssprache für Seitenvorlagen) erfahren. In diesem Abschnitt gehen wir nun detailliert auf alle TAL-Anweisungen und ihre Optionen ein. Eine Zusammenstellung dieses Materials finden Sie in Anhang C, "Zope-Page-Templates-Referenz".

Inhaltseingabe

Nachdem Sie in Kapitel 5, "Zope-Seitenvorlagen verwenden", bereits gesehen haben, wie tal:content und tal:replace funktionieren, werden Sie in diesem Abschnitt einige darauf aufbauende Tricks zum Einfügen von Inhalt kennen lernen.

Strukturen einbetten

Normalerweise setzen die Anweisungen tal:replace und tal:content HTML-Tags und -Entitäten im einzufügenden Text außer Kraft, d. h. sie konvertieren HTML-Auszeichnungen in Text. So wandeln sie zum Beispiel < in < um. Möchten Sie diese Umwandlung vermeiden, den Text also als Teil der HTML-Struktur eingeben, so stellen Sie dem Ausdruck das Schlüsselwort structure voran. Beispiel:

    

die Geschichte

Diese Funktion ist nützlich, wenn Sie ein HTML- oder XML-Fragment einfügen, das in einer Eigenschaft gespeichert ist oder von einem anderen Zope-Objekt erzeugt wurde. Nehmen wir zum Beispiel an, Sie haben Nachrichtenmeldungen, die einfache HTML-Auszeichnungen, z. B. für Fett- und Kursivschrift, enthalten, und diese Auszeichnungen möchten Sie auch beibehalten, wenn Sie die Meldungen in eine "Top-News"-Seite einfügen. Dafür schreiben Sie:

    

Eine Meldung mit HTML-Auszeichnungen.

Dieser Code fügt die HTML-Auszeichnungen der Nachrichtenmeldungen in eine Reihe von Absätzen ein.

Blindelemente

Seitenelemente, die zwar in der Vorlage, nicht aber im erzeugten Text sichtbar sind, fügen Sie mit der integrierten Variable nothing ein. Hierzu ein Beispiel:

    
        10213
Beispielelement
$15.34
    

Dieses Verfahren ist insbesondere dann nützlich, wenn Sie Seitenbereiche ausfüllen möchten, die mit dynamischem Inhalt gefüllt werden sollen. So hat zum Beispiel eine Tabelle, die normalerweise zehn Zeilen enthält, in der Seitenvorlage nur eine Zeile. Fügt man nun aber 9 Blindzeilen ein, so hat das Layout der Vorlage weit größere Ähnlichkeit mit dem Endergebnis.

Nicht immer müssen Sie auf tal:replace="nothing" zurückgreifen, um Blindinhalt in Ihre Seitenvorlagen einzufügen. So haben Sie zum Beispiel bereits gesehen, dass alles innerhalb der Elemente tal:content und tal:replace normalerweise entfernt wird, wenn die Seitenvorlage umgesetzt wird. Bei diesen Elementen sind also keine zusätzlichen Verfahren nötig, um den Blindinhalt zu entfernen.

Standardinhalt

Sie können den Inhalt eines Elements bestehen lassen, indem Sie den Ausdruck default zusammen mit tal:content oder tal:replace verwenden. Hierzu ein Beispiel:

          

Spam

Dieser Code wird folgendermaßen umgesetzt:

          

Spam

Meist möchte man Standardinhalt nicht generell einfügen, sondern nur, wenn bestimmte Bedingungen erfüllt sind. Ein Beispiel:

          

Dosenfleisch

Hinweis: Python-Ausdrücke werden weiter unten in diesem Kapitel erklärt. Falls die Methode holeEssen einen wahren Wert zurückgibt, wird ihr Ergebnis in den Absatz eingefügt; ansonsten ist das Ergebnis Dosenfleisch zum Abendessen.

Wiederholung

Die meisten Dinge, die Sie mit der Anweisung tal:repeat machen können, haben Sie bereits in Kapitel 5, "Zope-Seitenvorlagen verwenden", kennen gelernt. Dieser Abschnitt behandelt einige weiterführende Funktionen der Anweisung tal:repeat.

Wiederholungsvariablen

Die Wiederholungsvariablen gehören zu denjenigen Themen, die eventuell einer ausführlicheren Erläuterung bedürfen. Sie stellen Informationen über die aktuelle Wiederholung bereit. Für repeat-Variablen stehen die folgenden Attribute zur Verfügung:

  • index - Nummer der Wiederholung, beginnend bei null
  • number - Nummer der Wiederholung, beginnend bei eins
  • even - wahr für geradzahlig indizierte Wiederholungen (0, 2, 4, ...)
  • odd - wahr für ungeradzahlig indizierte Wiederholungen (1, 3, 5, ...)
  • start - wahr für die Anfangswiederholung (Index 0)
  • end - wahr für die abschließende (letzte) Wiederholung
  • length - Länge der Folge, also die Gesamtzahl der Wiederholungen
  • letter - Anzahl der Wiederholungen mit Kleinbuchstaben: "a" - "z", "aa" - "az", "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz", und so weiter
  • Letter - wie letter, aber für Großbuchstaben

Auf den Inhalt einer Wiederholungsvariablen können Sie mit Pfadausdrücken oder Python-Ausdrücken zugreifen. Ein Pfadausdruck ist die dreiteilige Angabe eines Pfades: Name der Variablen repeat, Name der Anweisungsvariablen, Name der gewünschten Information; also zum Beispiel repeat/item/start. In Python-Ausdrücken rufen Sie zuerst mit Hilfe der normalen Wörterbuchnotation die Wiederholungsvariable ab, und dann über den Attributzugriff die gewünschte Information. Zum Beispiel: 'python:repeat['item'].start'.

Tipps für die Wiederholung

Der folgende Abschnitt erläutert einige nützliche Tipps. Manchmal möchte man ein Tag wiederholen, allerdings ohne umschließendes Tag. Nehmen wir zum Beispiel an, Sie möchten eine Reihe von Absatz-Tags wiederholen, ohne sie in ein anderes Tag einzuschließen. Dafür verwenden Sie die Anweisung tal:omit-tag: pre>

Zitat

Die Anweisung tal:omit-tag wird weiter unten in diesem Kapitel erklärt.

Der folgende Tipp wurde bereits einmal erwähnt: tal:repeat-Anweisungen dürfen geschachtelt werden. Dabei muss jedes tal:repeat einen eindeutigen Wiederholungs-Variablennamen haben. Das folgende Beispiel zeigt eine Multiplikationstabelle:

          
X x Y = Z

Dieses Beispiel verwendet Python-Ausdrücke sowie die Anweisung tal:omit-tag. Beide werden weiter unten in diesem Kapitel näher erklärt.

Falls Sie bereits mit der DTML-Wiederholungsanweisung dtml-in gearbeitet haben, ist Ihnen der Begriff "Stapelung" (Batching) sicher schon untergekommen. Als Stapelung wird die Aufteilung einer großen Liste in mehrere kleinere Listen bezeichnet. In der Regel verwendet man dieses Verfahren, um auf einer Web-Seite nur einen Teil der Elemente einer umfangreichen Liste anzuzeigen. Ein anschauliches Beispiel sind Suchmaschinen, die die große Menge der Suchergebnisse in kleinere Gruppen zerlegen. Die Anweisung tal:repeat unterstützt die Stapelung zwar nicht, doch Zope enthält ein Stapelprogramm. Weitere Informationen dazu finden Sie im Abschnitt "Stapelung" weiter unten in diesem Kapitel.

Eine weitere nützliche Funktion, die von tal:repeat nicht bereitgestellt wird, ist das Sortieren. Möchten Sie eine Liste sortieren, so können Sie entweder ein eigenes Sortierskript schreiben (in Python ist das ganz einfach) oder die Funktion sequence.sort verwenden. Das folgende Beispiel zeigt, wie man eine Liste von Objekten auf dem Titel und dem Änderungsdatum sortiert.

          
Titel Änderungsdatum

Dieses Beispiel ist sehr übersichtlich, da es die Argumente für die Sortierung außerhalb der Funktion sort definiert. Die Funktion sequence.sort nimmt eine Folge sowie eine Beschreibung, wie diese Folge sortiert werden soll, entgegen. In diesem Beispiel ist die Beschreibung des Sortiervorgangs in der Variablen sort_on definiert. Weitere Informationen zu der leistungsstarken Funktion sequence.sort finden sie im Anhang B, "API-Referenz".

Attributsteuerung

Die Anweisung tal:attributes kennen Sie bereits. Mit Hilfe dieser Anweisung können Sie Tag-Attribute wie z. B. das Attribut href eines Elementes a dynamisch ersetzen. Auch das Ersetzen mehrerer Attribute eines Tags ist möglich. Dabei werden die Attribute durch Semikola voneinander getrennt:

        Link

Auch mit XML-Namensräumen können Sie Attribute definieren:

        
          Beschreibung

Um Attribute mit XML-Namensräumen zu erstellen, setzen Sie einfach das XML-Namensraumpräfix vor den Attributnamen.

Variablen definieren

Mit dem Attribut tal:define können Sie eigene Variablen definieren. Dies kann aus mehreren Gründen wünschenswert sein, zum Beispiel wenn ein langer Ausdruck innerhalb einer Vorlage immer wieder vorkommt oder eine aufwändige Methode häufig aufgerufen wird. Eine Variable wird nur einmal definiert, und kann dann in einer Vorlage beliebig oft verwendet werden. Die folgende Liste definiert eine Variable , prüft sie und wiederholt auf ihr:

        
  • ID

Die Anweisung tal:define erstellt die Variable items, die an beliebiger Stelle im Tag ul verwendet werden kann. Achten Sie in diesem Beispiel auch darauf, dass zwei TAL-Anweisungen innerhalb desselben ul-Tags eingesetzt werden. Im Abschnitt "Interaktionen zwischen TAL-Anweisungen" weiter unten in diesem Kapitel finden Sie weitere Informationen zur Verwendung mehrerer Anweisungen innerhalb eines Tags. In diesem Fall weist die erste Anweisung die Variable items zu, während die zweite Anweisung in einer Bedingung prüft, ob items wahr oder falsch (eine leere Folge) ist. Ist die Variable items falsch, so wird das Tag ul nicht angezeigt.

Gehen wir nun davon aus, dass Sie die Liste, falls sie keine Elemente enthält, nicht einfach entfernen, sondern stattdessen eine Meldung ausgeben möchten. Hierfür fügen Sie vor der Liste den folgenden Code ein:

        

Keine Elemente vorhanden

Der Ausdruck not:container/objectIds ist dann wahr, wenn container/objectIds falsch ist, und umgekehrt. Weitere Informationen dazu finden Sie im Abschnitt "not-Ausdrücke" weiter unten in diesem Kapitel.

Hier können Sie die Variable items nicht verwenden, da sie an dieser Stelle noch nicht definiert ist. Verschieben Sie die Definition von items jedoch in das Tag h4, so können Sie sie im Tag ul nicht mehr verwenden, da sie in diesem Fall eine lokale Variable von h4 ist. Sie könnten die Definition zwar in ein Tag einfügen, das sowohl h4 als auch ul einschließt, doch es gibt auch eine einfachere Möglichkeit. Stellen Sie dem Variablennamen das Schlüsselwort global voran, so ist die Definition vom Tag h4 bis zum Ende der Vorlage gültig:

        

Keine Elemente vorhanden

Mit tal:define können Sie auch mehrere Variablen gleichzeitig definieren, indem Sie diese durch Semikola voneinander trennen:

        

Auf diese Art können Sie beliebig viele Variablen definieren. Jede dieser Variablen kann einen eigenen globalen oder lokalen Gültigkeitsbereich haben. Außerdem können Sie in einer Definition auf zuvor bereits definierte Variablen verweisen:

        

Wie Sie sehen, kann der gezielte Einsatz von tal:define die Effizienz und Lesbarkeit einer Vorlage wesentlich verbessern.

Tags entfernen

Mit der Anweisung tal:omit-tag können Sie Tags entfernen. Diese TAL-Anweisung kommt nur selten zum Einsatz, kann gelegentlich aber durchaus nützlich sein. Das Attribut omit-tag entfernt ein Tag, hat aber keinerlei Auswirkungen auf den Inhalt dieses Tags. Hierzu ein Beispiel:

        this bleibt

Dieser Code wird umgesetzt als:

        dies bleibt

Wird tal:omit-tagauf diese Art eingesetzt, so funktioniert es fast wie tal:replace="default". Allerdings ist tal:omit-tag nützlicher, wenn es zusammen mit anderen TAL-Anweisungen wie z. B. tal:repeat verwendet wird. Das folgende Beispiel zeigt eine Möglichkeit, mit tal:repeat zehn Absatz-Tags zu erstellen:

        
          

1

Dieser Code erstellt zehn Absatz-Tags, wobei das Tag span nicht mit ausgegeben wird.

Das Attribut tal:omit-tag nimmt einen Ausdruck entgegen, wobei in der Regel allerdings ein leerer Ausdruck verwendet wird. Ist der Ausdruck wahr oder gibt es keinen Ausdruck, so wird das Ausdrucks-Tag entfernt. Ist der Ausdruck falsch, so wird das Tag nicht entfernt. Dieses Attribut gibt Ihnen also die Möglichkeit, Tags nur unter bestimmten Umständen zu entfernen.

Fehlerbehandlung

Falls in Ihrer Seitenvorlage ein Fehler auftrifft, können Sie diesen abfangen und eine sinnvolle Fehlermeldung ausgeben. Nehmen wir zum Beispiel an, dass die Vorlage anhand von Formulardaten eine Variable definiert:

        ...
        
        ...

Stößt Zope auf ein Problem, kann es zum Beispiel die Variable prefs in den Formulardaten nicht finden, so wird der gesamte Seitenaufbau abgebrochen und stattdessen eine Fehlerseite ausgegeben. Zum Glück lässt sich dies durch eine eingeschränkte Fehlerbehandlung mit der Anweisung tal:on-error vermeiden:

        ...
        
        ...

Tritt während der Umsetzung einer Vorlage ein Fehler auf, so sucht Zope nach einer tal:on-error-Anweisung, um den Fehler zu behandeln. Zuerst sucht es im aktuellen Tag, dann im umschließenden Tag und so weiter, bis es schließlich die oberste Ebene erreicht. Findet Zope einen Fehlerbehandler, so ersetzt es den Inhalt des betroffenen Tags durch diesen Ausdruck für die Fehlerbehandlung. In diesem Fall enthält das Tag span dann eine Fehlermeldung.

Normalerweise wird ein Fehlerbehandler auf einem Tag definiert, das ein logisches Seitenelement umschließt, also z. B. auf einer Tabelle. Falls ein Fehler auftritt, während die Tabelle gezeichnet wird, kann der Fehlerbehandler die Tabelle einfach aus der Seite entfernen oder sie durch eine Fehlermeldung ersetzen.

Eine flexiblere Fehlerbehandlung wird durch den Aufruf eines Skripts ermöglicht:

        
...

Jeder Fehler, der innerhalb von div auftritt, ruft das Skript handleError auf. Beachten Sie, dass es die Option structure dem Skript ermöglicht, zu HTML zurückzukehren. Das Skript zur Fehlerbehandlung kann den Fehler untersuchen und je nachdem, um welchen Fehler es sich handelt, unterschiedliche Maßnahmen ergreifen. Das Skript greift über die Variable error im Namensraum auf den Fehler zu. Hierzu ein Beispiel:

        ## Script (Python) "handleError"
        ##binde Namensraum=_
        ##
        error=_['error']
        if error.type==ZeroDivisionError:
            return "

Kann nicht durch null teilen.

" else return """

Ein Fehler ist aufgetreten.

Fehlertyp: %s

Fehlerwert: %s

""" % (error.type, error.value)

Das Skript zur Fehlerbehandlung kann beliebige Aktionen durchführen. So kann es zum Beispiel ein Fehlerprotokoll per E-Mail abschicken.

Die Anweisung tal:on-error ist nicht auf eine allgemeine Ausnahmebehandlung angelegt. Zum Beispiel ist sie nicht für die Validierung von Formulareingaben geeignet. Diese sollte mit einem Skript durchgeführt werden, da Skripte eine leistungsstarke Ausnahmebehandlung ermöglichen. Die Anweisung tal:on-error dient lediglich der Behandlung ungewöhnlicher Probleme, die bei der Umsetzung von Vorlagen auftreten können.

Interaktionen zwischen TAL-Anweisungen

Gibt es für jedes Element nur eine einzige TAL-Anweisung, so folgt deren Ausführung einer einfachen Logik: Zuerst wird die Anweisung des Wurzelelementes ausgeführt, dann werden der Reihe nach alle Kindelemente geprüft und ihre Anweisungen ausgeführt.

Es ist allerdings auch möglich, dass es auf einem Element mehr als eine TAL-Anweisung gibt. Dabei ist mit Ausnahme der Anweisungen tal:content und tal:replace, die nicht gemeinsam verwendet werden dürfen, jede Kombination von Anweisungen möglich.

Verfügt ein Element über mehrere Anweisungen, so werden diese in der folgenden Reihenfolge ausgeführt:

  1. define
  2. condition
  3. repeat
  4. content oder replace
  5. attributes
  6. omit-tag

Die Anweisung tal:on-error wird hier nicht genannt, da sie nur aufgerufen wird, wenn ein Fehler auftritt.

Diese Reihenfolge ist natürlich nicht willkürlich festgelegt. Häufig definiert man Variablen, um sie dann in anderen Anweisungen zu verwenden. Daher steht define an erster Stelle. Anschließend muss man entscheiden, ob dieses Element überhaupt aufgenommen wird, wofür condition zuständig ist. Da die jeweilige Bedingung von gerade definierten Variablen abhängen kann, folgt condition direkt hinter define. Es ist nützlich, wenn man bestimmte Teile eines Elements bei jeder Iteration von repeat durch andere Werte ersetzen kann. Daher steht repeat vor content, replace und attributes. Da content und replace nicht auf demselben Element ausgeführt werden können, stehen sie nebeneinander. Die Anweisung omit-tag steht an letzter Stelle, da es höchst unwahrscheinlich ist, dass irgendeine andere Anweisung von ihr abhängt, und sie nach repeat aufgeführt werden sollte.

Das folgende Beispiel-Tag enthält mehrere TAL-Anweisungen:

        

Ex Text

Beachten Sie, dass die Anweisung tal:define zuerst ausgeführt wird und die anderen Anweisungen von ihrem Ergebnis abhängen.

Wenn Sie TAL-Anweisungen auf Elementen kombinieren, sollten Sie die folgenden drei Einschränkungen beachten:

  1. Da HTML die Ausführung mehrerer Attribute mit demselben Namen verbietet, kann auf einem bestimmten Tag nur eine Instanz eines Anweisungstyps ausgeführt werden. So ist es zum Beispiel nicht möglich, zwei Instanzen von tal:define auf demselben Tag auszuführen.
  2. Da die Funktionen von tal:content und tal:replace nicht miteinander vereinbar sind, kann auf jedem Tag nur eine dieser beiden Anweisungen ausgeführt werden.
  3. Die Reihenfolge, in der TAL-Attribute auf einem Tag notiert werden, hat keinerlei Einfluss auf die Reihenfolge ihrer Ausführung. Unabhängig von ihrer Anordnung werden die TAL-Anweisungen auf einem Tag immer in der oben genannten Reihenfolge ausgeführt.

Möchten Sie die Reihenfolge von TAL-Anweisungen überschreiben, so müssen Sie das Element in ein anderes Element einschließen, z. B. in div oder span, und einige der Anweisungen in dieses neue Element einfügen. Nehmen wir z. B. an, Sie möchten eine Folge von Objekten mit einer Schleife durchlaufen, dabei aber einige der Objekte überspringen. Eine Vorlage, die die Zahlen 0 bis 9 mit einer Schleife durchläuft und dabei die 3 überspringt, könnte folgendermaßen aussehen:

        
        
  • 1

Diese Vorlage funktioniert nicht, da die Bedingung vor der Ausführung von repeat geprüft wird. Anders ausgedrückt: Die Variable n soll zuerst geprüft und danach erst definiert werden. Dieses Problem lässt sich folgendermaßen umgehen:

        
  • 1

Diese Vorlage löst das Problem, indem sie die Variable n auf einem umschließenden div-Tag definiert. Beachten Sie, dass das Tag div nicht in die Ausgabe übernommen wird, da es die Anweisung tal:omit-tag enthält. Dieser Code sieht zwar nicht schön aus, funktioniert aber. Möglicherweise werden zukünftige Seitenvorlagen-Versionen eine attraktivere Lösung dieses Problems anbieten.

Formularverarbeitung

In DTML können Sie Formulare mit einem einfachen Muster verarbeiten, dem so genannten "Formular-/Aktionspaar". Ein Formular-/Aktionspaar besteht aus zwei DTML-Methoden oder Dokumenten: Die bzw. das erste enthält ein Formular, das eine Eingabe des Anwenders entgegennimmt, und die bzw. das zweite enthält eine Aktion, die auf dieser Eingabe ausgeführt wird, und gibt eine Antwort aus. Das Formular ruft die Aktion auf. Weitere Informationen zum Formular-/Aktionsmuster finden Sie in Kapitel 4, "Dynamischer Inhalt mit DTML".

In Zope-Seitenvorlagen lässt sich das Formular-/Aktionsmuster nicht sonderlich gut einsetzen, da es davon ausgeht, dass die Verarbeitung der Eingabe und die Darstellung der Antwort von demselben Objekt (der Aktion) gehandhabt werden. Anstelle des Formular-/Aktionsmusters empfiehlt sich daher die Verwendung eines Formular-/Aktions-/Antwortmusters. Dabei sollten das Formular und die Antwort Seitenvorlagen sein, die Aktion hingegen ein Skript, das die Eingabe verarbeitet und eine Antwortvorlage zurückgibt. Dieses Muster ist flexibler als das Formular-/Aktionsmuster, da das Skript ein beliebiges Objekt aus einer Gruppe von Antwortobjekten zurückgeben kann.

Das folgende Beispiel veranschaulicht eine Formularvorlage:

        ...
        
...

Für die Verarbeitung des Formulars könnte ein Skript wie das folgende zuständig sein:

        ## Script (Python) "action"
        ##Parameter=name, age
        ##
        container.addPerson(name, age)
        return container.responseTemplate()

Dieses Skript ruft eine Methode für die Verarbeitung der Eingabe auf und gibt eine weitere Vorlage zurück, die die Antwort enthält. Durch den Aufruf dieses Skripts können Sie eine Seitenvorlage aus Python umsetzen. Die Antwortvorlage enthält normalerweise die Bestätigung, dass das Formular richtig verarbeitet wurde.

Das Aktionsskript kann alle möglichen Aktionen durchführen. Es kann eine Eingabe prüfen, Fehler behandeln, E-Mails verschicken usw. Das folgende Beispiel zeigt, wie eine Eingabe mit einem Skript geprüft wird:

        ## Script (Python) "action"
        ##
        if not context.validateData(request):
            # Tritt ein Problem auf, so gib die Formularseitenvorlage
            # zusammen mit einer Fehlermeldung zurück
            return context.formTemplate(error_message='Invalid data')

        # Ansonsten gib die Dankesseite zurück
        return context.responseTemplate()

Dieses Skript prüft die Formulareingabe und gibt die Formularvorlage mit einer Fehlermeldung zurück, falls ein Problem aufgetreten ist. An Seitenvorlagen können Sie Zusatzinformationen mit Schlüsselwortargumenten übergeben. Die Schlüsselwortargumente stehen der Vorlage über die integrierte Variable options zur Verfügung. Die Formularvorlage kann also einen Abschnitt wie den folgenden enthalten:

        
          Hier folgt die Fehlermeldung.
        

Dieses Beispiel zeigt, wie Sie eine Fehlermeldung ausgeben können, die über Schlüsselwortargumente an die Vorlage übergeben werden.

Je nach Anwendung können Sie den Anwender auch an eine Antwortseitenvorlage weiterleiten, statt diese direkt zurückzugeben. Obwohl dies die Netzwerkaktivität verdoppelt, ist es durchaus sinnvoll, da hierbei im Browser des Anwenders nicht der URL des Aktionsskripts angezeigt wird, sondern der der Seitenvorlage.

Falls Sie keinen Wert auf saubere Formularverarbeitung legen, können Sie mit Ihren Seitenvorlagen auch eine eingeschränkte Version des Formular-/Aktionspaares verwenden. Dies sollten Sie allerdings wirklich nur dann machen, wenn Ihnen an einer Fehlerbehandlung nicht gelegen ist und die Antwort in jedem Fall, unabhängig von der jeweiligen Eingabe des Anwenders, dieselbe ist. Da Seitenvorlagen keine Entsprechung zu dtml-call haben, können Sie einen Trick anwenden, um eine Methode zur Eingabeverarbeitung aufzurufen, ohne deren Ergebnisse einzufügen. Hierzu ein Beispiel:

        

Dieses Beispiel ruft die Methode processInputs auf und weist ihr Ergebnis der Variable unused zu.

Ausdrücke

Seitenvorlagenausdrücke haben Sie bereits kennen gelernt. Ausdrücke stellen Werte für Vorlagenanweisungen bereit. Ein Beispiel sind Pfadausdrücke, die Objekte durch einen Pfad wie request/form/age oder user/getUserName beschreiben. Dieser Abschnitt erklärt die verschiedenen Arten von Ausdrücken und Variablen.

Integrierte Variablen

Variablen sind Namen, die in Ausdrücken verwendet werden können. Sie haben bereits einige Beispiele für integrierte Variablen kennen gelernt, z. B. template, user, repeat und request. Die folgende Liste nennt alle weiteren integrierten Variablen und ihre Verwendungsweise.

nothing
Ein false-Wert, ähnlich einer leeren Zeichenkette, den Sie in tal:replace oder tal:content verwenden können, um ein Tag oder seinen Inhalt zu löschen. Es besteht allerdings ein Unterschied zu leeren Zeichenketten: Wenn Sie ein Attribut auf nothing setzen, wird dieses Attribut aus dem Tag gelöscht (oder nicht eingefügt).
default
Ein besonderer Wert, der nichts ändert, wenn er in tal:replace, tal:content oder tal:attributes verwendet wird. Er beeinflusst den Vorlagentext nicht.
options
Die an die Vorlage übergebenen Schlüsselwortargumente, sofern vorhanden. Hinweis: options steht nur zur Verfügung, wenn eine Vorlage aus Python ausgerufen wird. Wird sie aus dem Internet umgesetzt, so gibt es keine Optionen.
attrs
Ein Attributwörterbuch des aktuellen Tags in der Vorlage. Als Schlüssel dienen die Attributnamen und als Werte die ursprünglichen Werte der Attribute in der Vorlage. Diese Variable kommt selten zum Einsatz.
root
Das Zope-Wurzelobjekt. Damit werden Zope-Objekte von festen Speicherorten geholt, unabhängig davon, wo die Vorlage platziert oder aufgerufen wird.
here
Das Objekt, auf dem die Vorlage aufgerufen wird. Häufig ist es mit dem Behälter identisch; falls Sie mit Akquisition arbeiten, kann here allerdings auch ein anderes Objekt bezeichnen. Mit dieser Variable werden Zope-Objekte abgerufen, die sich je nachdem, wie die Vorlage aufgerufen wird, an verschiedenen Stellen befinden können. here entspricht der Variable context in Python-basierten Skripten.
container
Der Behälter (normalerweise ein Ordner), in dem sich die Vorlage befindet. Mit dieser Vorlage werden Zope-Objekte von Speicherorten abgerufen, der relativ zum dauerhaften Speicherort der Vorlage angegeben ist. Die Variablen container und here verweisen auf dasselbe Objekte, falls eine Schablone von ihrem dauerhaften Speicherort aufgerufen wird. Wird eine Vorlage allerdings auf ein anderes Objekt (z. B. eine ZSQL-Methode) angewandt, so verweisen container und here nicht auf dasselbe Objekt.
modules
Die Sammlung von Python-Modulen, die Vorlagen zur Verfügung stehen. Weitere Informationen dazu finden Sie im Abschnitt über Python-Ausdrücke.

Dieses Kapitel enthält eine Reihe von Beispielen für die Verwendung dieser Variablen.

Zeichenkettenausdrücke

Zeichenkettenausdrücke ermöglichen die problemlose Verbindung von Pfadausdrücken und Text. Der gesamte Text nach dem öffnenden Tag string: wird auf Pfadausdrücke hin durchsucht. Jedem Pfadausdruck muss ein Dollar-Zeichen ('$') vorangestellt sein:

        "string:Nur Text. Kein Pfad."
        "string:copyright $year, ich."

Besteht der Pfadausdruck aus mehreren Teilen oder muss er vom danach folgenden Text abgetrennt werden, so wird er in geschweifte Klammern ('{}') gesetzt:

        "string:Drei ${Birne}n, bitte."
        "string:Ihr Name ist ${user/getUserName}!"

Achten Sie bei diesem Beispiel darauf, dass der Pfad Birne in geschweifte Klammern gesetzt werden muss, damit Zope ihn nicht mit Birnen verwechselt.

Da sich der Text innerhalb eines Attributwerts befindet, können Sie doppelte Anführungszeichen nur mit Hilfe der Entitätssyntax " einfügen. Kommt im Text ein Dollar-Zeichen vor, so muss es verdoppelt werden ('$$'), weil das einfache Dollar-Zeichen Pfadausdrücke kennzeichnet:

        "string:Bitte bezahlen Sie $$$dollars_owed"
        "string:Sie sagte: "Hallo Welt.""

Einige komplexe Formatierungsoptionen für Zeichenketten (z. B. Suchen und Ersetzen oder Umwandlung in Großbuchstaben) können mit Zeichenkettenausdrücken problemlos umgesetzt werden. Am besten sind hierfür Python-Ausdrücke oder Skripte geeignet.

Pfadausdrücke

Pfadausdrücke verweisen mit einem URL-ähnlichen Pfad auf Objekte. Ein Pfad beschreibt den Weg von einem Objekt zu einem anderen Objekt. Alle Pfade beginnen mit einem bekannten Objekt (z. B. einer integrierten Variable, einer Wiederholungsvariable oder einer benutzerdefinierten Variable) und gehen von dort aus zum gewünschten Objekt. Einige Beispiele für Pfadausdrücke:

        template/title
        container/files/objectValues
        user/getUserName
        container/master.html/macros/header
        request/form/address
        root/standard_look_and_feel.html

Pfadausdrücke ermöglichen den Wechsel von einem Objekt zu seinen Unterobjekten einschließlich der Eigenschaften und Methoden. Auch die Akquisition kann in Pfadausdrücken verwendet werden. Weitere Informationen zur Akquisition und Pfaddurchquerung finden Sie im Abschnitt "Skripte aus dem Internet aufrufen" in Kapitel 10, "Zope-Scripting für Fortgeschrittene"; und in Kapitel 7, "Benutzer und Sicherheit", erfahren Sie mehr über die Objektzugriffssteuerung.

Alternative Pfade

Der Pfad template/title besteht immer, wenn die Vorlage verwendet wird, kann allerdings eine leere Zeichenkette sein. Andere Pfade, z. B. request/form/x, gibt es bei bestimmten Umsetzungen der Schablone nicht. In diesem Fall tritt ein Fehler auf, wenn Zope den Pfadausdruck auswertet.

Gibt es einen bestimmten Pfad nicht, so können Sie einen Ersatzpfad oder -wert einrichten, der statt dieses Pfades verwendet werden soll. Existiert z. B. request/form/x nicht, so können Sie here/x als Alternative festlegen. Um einen alternativen Pfad zu definieren, geben Sie eine Liste von Pfaden an, die nach Priorität geordnet und durch senkrechte Striche ('|') voneinander abgetrennt werden:

          

Header

Als letztes Element einer Liste alternativer Pfade sind besonders die Variablen nothing und default sinnvoll. In diesem Fall teilt z. B. default der Anweisung tal:content mit, dass der Blindinhalt unverändert bleiben soll. Andere TAL-Anweisungen interpretieren default und nothing anders. Weitere Informationen hierzu finden Sie in Anhang C, "Zope-Page-Templates-Referenz".

Der letzte Teil eines Alternativpfadausdrucks kann auch ein Nicht-Pfadausdruck sein, zum Beispiel:

          

Alter

Existiert in diesem Beispiel der Pfad request/form/age nicht, so ist der Wert die Zahl 18. Dieses Formular ermöglicht die Angabe von Standardwerten, die nicht als Pfade ausgedrückt werden können. Beachten Sie, dass Sie Nicht-Pfadausdrücke nur als letzte Alternative verwenden können.

Mit dem Ausdruckstyppräfix exists kann direkt geprüft werden, ob ein Pfad existiert. Weitere Informationen zu exists-Ausdrücken finden Sie im Abschnitt "exists-Ausdrücke" weiter unten in diesem Kapitel.

not-Ausdrücke

Mit not-Ausdrücken können Sie den Wert anderer Ausdrücke negieren. Hierzu ein Beispiel:

        

Hier sind keine Objekte enthalten.

Ist der Ausdruck, auf den ein not-Ausdruck angewendet wird, falsch, so gibt der not-Ausdruck true zurück, und umgekehrt. In Zope werden nicht vorhandene Variablen, null, leere Zeichenketten, leere Folgen, nothing und None als falsch gewertet, alles andere als wahr.

In Verbindung mit Python-Ausdrücken wird normalerweise kein not-Ausdruck verwendet, sondern das Python-Schlüsselwort not.

nocall-Ausdrücke

Ein gewöhnlicher Pfadausdruck versucht das Objekt, das er abruft, umzusetzen. Falls das Objekt eine Funktion, ein Skript, eine Methode oder ein anderes ausführbares Objekt ist, bedeutet dies, dass der Ausdruck als das Ergebnis des Objektaufrufs ausgewertet wird. Dies ist zwar meist das gewünschte Ergebnis, aber nicht immer. Möchte man z. B. ein DTML-Dokument in eine Variable einfügen, um auf seine Eigenschaften verweisen zu können, so kann man dafür keinen normalen Pfadausdruck verwenden, da dieser das Dokument in eine Zeichenkette umwandelt.

Setzt man einem Pfad das Ausdruckstyppräfix nocall: voran, so wird die Umsetzung unterbunden und nur das Objekt abgerufen. Hierzu ein Beispiel:

        
        ID: Titel

Dieser Ausdruckstyp ist auch nützlich, wenn Sie eine Variable definieren möchten, die zur Weiterverwendung in einem Python-Ausdruck eine Funktion oder Klasse aus einem Modul enthalten soll.

Nicht nur auf Objekten, sondern auch auf Funktionen können nocall-Ausdrücke verwendet werden:

        

Dieser Ausdruck definiert die Variable join nicht als Ergebnis eines Funktionsaufrufs, sondern als Funktion ('string.join').

exists-Ausdrücke

Ein exists-Ausdruck ist dann wahr, wenn sein Pfad existiert; ansonsten ist er falsch. Das folgende Beispiel zeigt eine Möglichkeit, eine Fehlermeldung nur dann auszugeben, wenn sie in der Anfrage übergeben wird:

        

Fehler!

Mit einem exists-Ausdruck erzielen Sie dasselbe Ergebnis auf einfachere Art:

        

Fehler!

Auch eine Kombination von not- und exists-Ausdrücken ist möglich:

        

Geben Sie bitte eine Zahl zwischen 0 und 5 ein.

Beachten Sie, dass der Ausdruck "not:request/form/number" in diesem Beispiel nicht verwendet werden kann, da er wahr ist, falls die Variable number existiert und den Wert null hat.

Python-Ausdrücke

Python ist eine einfache und ausdrucksstarke Programmiersprache. Falls Sie bisher noch nicht damit gearbeitet haben, sollten Sie eine der hervorragenden Einführungen lesen, die Sie auf der Python-Website finden.

Ein Python-Ausdruck für Seitenvorlagen kann alles enthalten, was Python als einen Ausdruck erkennt. Nicht verwendet werden dürfen Anweisungen wie zum Beispiel if und while. Außerdem erzwingt Zope einige sicherheitsrelevante Einschränkungen, um den Zugriff auf geschützte Informationen, die Änderung gesicherter Daten und die Einführung problematischer Verfahren (z. B. Endlosschleifen) zu verhindern. Weitere Informationen zu Sicherheitsrestriktionen für Python finden Sie in Kapitel 10, "Zope-Scripting für Fortgeschrittene".

Vergleich

In einigen Fällen sind Python-Ausdrücke fast unumgehbar. Hierzu gehört z. B. die Anweisung tal:condition. Normalerweise vergleicht man zwei Zeichenketten oder Zahlen, und dies ist nur mit Python-Ausdrücken möglich. Sie können die Vergleichsoperatoren < (kleiner als), > (größer als), == (ist gleich) und != (ist nicht gleich) sowie die Booleschen Operatoren and, not und or verwenden. Beispiele:

          

1: Name

Dieses Beispiel durchläuft eine Sammlung von Objekten mit einer Schleife und prüft dabei das Attribut type der einzelnen Objekte.

Manchmal möchte man innerhalb einer Anweisung anhand einer oder mehrerer Bedingungen verschiedene Werte wählen. Dies ist mit der Funktion test möglich:

          Sie 
                sind angemeldet als
                Name
              

Die Funktion test funktioniert wie eine if/then/else-Anweisung. Weitere Informationen zu dieser Funktion finden Sie in Anhang A, "DTML-Referenz". Das folgende Beispiel veranschaulicht die Verwendung der Funktion test:

          
                

Ohne die Funktion test müssten Sie hier zwei tr-Elemente mit jeweils unterschiedlichen Bedingungen schreiben: eine für gerade Zeilen und eine für ungerade Zeilen.

Weitere Ausdruckstypen

Auch andere Ausdruckstypen können in einem Python-Ausdruck verwendet werden. Jedem Ausdruckstyp entspricht eine gleichnamige Funktion: path(), string(), exists() und nocall(). Somit kann man Ausdrücke wie die folgenden schreiben:

          "python:path('here/%s/thing' % foldername)"
          "python:path(string('here/$foldername/thing'))"
          "python:path('request/form/x') or default"

Das letzte Beispiel hat eine etwas andere Bedeutung als der Pfadausdruck "request/form/x | default", da es den Standardtext verwendet, falls "request/form/x" nicht existiert oder falsch ist.

Auf Zope-Objekte zugreifen

Zope ist vor allem auch deshalb so leistungsfähig, weil es spezialisierte Objekte miteinander verbindet. Seitenvorlagen können Skripte, SQL-Methoden, Kataloge und benutzerdefinierte Inhaltsobjekte verwenden. Um diese Objekte nutzen zu können, müssen Sie wissen, wie Sie in Seitenvorlagen auf sie zugreifen können.

Objekteigenschaften sind normalerweise Attribute. Daher ruft man den Titel einer Vorlage mit dem Ausdruck "template.title" ab. Die meisten Zope-Objekte unterstützen die Akquisition, die den Zugriff auf Attribute von Elternobjekten ermöglicht. Dies bedeutet, dass der Python-Ausdruck "here.Control_Panel" das Objekt Systemsteuerung aus dem Wurzelordner erwirbt. Objektmethoden sind Attribute, z. B. "here.objectIds" und "request.set". Auf Objekte in einem Ordner kann man als Attribute dieses Ordners zugreifen. Allerdings sind ihre Namen häufig keine zulässigen Python-Bezeichner, sodass man nicht die normale Notation verwenden kann. So ist z. B. dieser Python-Ausdruck nicht zulässig:

          "python:here.pinguin.gif"'. 

Stattdessen müssen Sie die folgende Notation verwenden:

          "python:getattr(here, 'pinguin.gif')"

Dies liegt daran, dass Python Attributnamen, die Punkte enthalten, nicht unterstützt.

Einige Objekte, z. B. request, modules und Zope-Ordner, unterstützten den Python-Elementzugriff:

          request['URL']
          modules['math']
          here['thing']

Wenn Sie den Elementzugriff auf einen Ordner anwenden, versucht er nicht, den Namen zu akquirieren, wird also nur dann erfolgreich durchgeführt, wenn der Ordner tatsächlich ein Objekt mit dem angegebenen Namen enthält.

In anderen Kapiteln wurde bereits gezeigt, dass Sie bei Pfadausdrücken Einzelheiten des Weges von einem Objekt zum nächsten ignorieren können. Zope versucht zuerst einen Attributzugriff, dann einen Elementzugriff. Anstatt

          "python:getattr(here.images, 'pinguin.gif')"

können Sie auch die folgende Schreibweise verwenden:

          "here/images/pinguin.gif"

ebenso auch

          "request/form/x" 

an Stelle von:

          "python:request.form['x']"

Der Nachteil ist, dass die Angabe dieser Einzelheiten bei Pfadausdrücken nicht möglich ist. Haben Sie z. B. eine Formularvariable namens "get", so müssen Sie

          "python:request.form['get']"

schreiben, da der Pfadausdruck

          "request/form/get" 

als die Methode "get" des Formularwörterbuches ausgewertet wird.

Mit der Funktion path() können Sie, wie oben beschrieben, Pfadausdrücke innerhalb von Python-Ausdrücken verwenden.

Mit Skripten arbeiten

Skriptobjekte werden häufig dafür verwendet, die Anwendungslogik und eine komplexe Datenbearbeitung zu kapseln. Schreiben Sie viele TAL-Anweisungen, die komplizierte Ausdrücke enthalten, so sollten Sie auf jeden Fall erwägen, stattdessen ein Skript zu verwenden. Bereitet es Ihnen Schwierigkeiten, Ihre Vorlagenanweisungen und -ausdrücke zu durchschauen, so sollten Sie die Vorlage vereinfachen und für die komplexen Bereiche Skripte verwenden.

Für jedes Skript gibt es eine Parameterliste, die dem Skript bei dessen Aufruf übergeben wird. Ist diese Liste leer, so können Sie das Skript dennoch verwenden, indem Sie einen Pfadausdruck angeben. Anderenfalls müssen Sie das Argument mit Hilfe eines Python-Ausdrucks bereitstellen:

          "python:here.myscript(1, 2)"
          "python:here.myscript('arg', foo=request.form['x'])"

Geben Sie aus einem Skript mehr als ein Datenelement an eine Seitenvorlage zurück, so ist die Rückgabe in einem Wörterbuch sinnvoll, denn dabei können Sie eine Variable definieren, die alle Daten enthält, und über Pfadausdrücke auf die einzelnen Daten verweisen. Nehmen wir z. B. an, dass das Skript getPerson ein Wörterbuch mit den Schlüsseln name und age zurückgibt:

          
          Name ist 30 Jahre alt.

Natürlich können auch Zope-Objekte und Python-Listen zurückgegeben werden.

DTML aufrufen

Im Gegensatz zu Skripten haben DTML-Methoden und -Dokumente keine ausdrückliche Parameterliste. Stattdessen müssen ihnen ein Client, eine Zuordnung und Schlüsselwortargumente übergeben werden. Anhand dieser Parameter erstellen sie dann einen Namensraum. Weitere Informationen zu ausdrücklichen DTML-Aufrufen finden Sie in Kapitel 7.

Wenn Zope ein DTML-Objekt über das Internet veröffentlicht, übergibt es den Inhalt des Objekts als Client und die Anfrage (REQUEST) als Zuordnung. Wenn ein DTML-Objekt ein anderes DTML-Objekt aufruft, übergibt es keinen Client und als Zuordnung seinen eigenen Namensraum.

Falls Sie ein DTML-Objekt über einen Pfadausdruck umsetzen, übergibt es einen Namensraum, der request, here und die Variablen der Vorlage bereits enthält. Dies bedeutet, dass das DTML-Objekt nicht nur dieselben Namen wie bei einer Veröffentlichung im Kontext der Vorlage verwenden kann, sondern auch die in der Vorlage definierten Variablennamen.

Python-Module

Die Programmiersprache Python enthält eine Vielzahl von Modulen, die Python-Programme flexibel und vielseitig machen. Jedes Modul ist eine Sammlung von Python-Funktionen, -Daten und -Klassen, die sich auf einen einzigen Zweck beziehen, z. B. auf mathematische Berechnungen oder reguläre Ausdrücke.

Einige Module, darunter "math" und "string", stehen in Python-Ausdrücken immer zur Verfügung. So können Sie zum Beispiel mit "python:math.pi" den Wert von pi aus dem Modul "math" abrufen. Um darauf aus einem Pfadausdruck heraus zuzugreifen, benötigen Sie hingegen die Variable modules: "modules/math/pi".

Da das Modul "string"in Python-Ausdrücken durch die Ausdruckstypfunktion "string" verborgen ist, benötigen Sie für den Zugriff auf das Modul die Variable modules. Dabei gibt es zwei Möglichkeiten, auf das Modul zuzugreifen: Entweder direkt in einem Ausdruck, in dem Sie es verwenden, oder, wie im folgenden Beispiel, über eine selbst definierte globale Variable.

          tal:define="global mstring modules/string"
          tal:replace="python:mstring.join(slist, ':')"

In der Praxis ist dies selten erforderlich. Meist braucht man sich nicht auf Funktionen im Modul "string" zu stützen, sondern kann stattdessen Zeichenkettenmethoden verwenden.

Module können zu Paketen zusammengefasst werden. Pakete stellen eine einfache Möglichkeit dar, verwandte Module zu organisieren und zu benennen. So werden z. B. die Python-basierten Skripte in Zope als eine Sammlung von Modulen im Unterpaket "PythonScripts" des Zope-Pakets "Products" bereitgestellt. Besonders das in diesem Paket enthaltene Modul "standard" bietet eine Reihe nützlicher Formatierungsfunktionen, die im DTML-Tag "var" regelmäßig eingesetzt werden. Der vollständige Name dieses Moduls ist "Products.PythonScripts.standard"; der Zugriff erfolgt demnach mit einer der folgenden Anweisungen:

          tal:define="global pps modules/Products/PythonScripts/standard"
          tal:define="global pps python:modules['Products.PythonScripts.standard']"

Auf die meisten Python-Module kann man nur dann aus Seitenvorlagen, DTML oder Skripten heraus zugreifen, wenn man diese um Zope-spezifische Sicherheitsmaßnahmen erweitert. Diese Verfahren können im Rahmen dieses Buches nicht besprochen werden; sie werden im Zope Developer's Guide näher erläutert.

Makros

Bisher haben Sie gesehen, wie Sie einzelnen Web-Seiten mit Seitenvorlagen dynamisches Verhalten hinzufügen können. Darüber hinaus ermöglichen Seitenvorlagen die Wiederverwendung von Darstellungselementen auf mehreren Seiten.

Mit Seitenvorlagen können Sie zum Beispiel eine Site mit einem einheitlichen Look&Feel einrichten: Unabhängig vom Inhalt der einzelnen Seiten erhalten alle Seiten identische Header, Footer, Seitenleisten und/oder andere Seitenelemente. Dies ist eine Anforderung, die häufig an Websites gestellt wird.

Mit Makros können Sie Darstellungselemente auf mehreren Seiten wiederverwenden. Makros definieren einen Seitenbereich, der in anderen Seiten wiederverwendet werden kann. Ein Makro kann ebenso gut eine ganze Seite wie ein kleiner Seitenbereich sein, also z. B. ein Header oder Footer. Nachdem Sie in einer Seitenvorlage ein oder mehrere Makros definiert haben, können Sie diese auch in anderen Seitenvorlagen verwenden.

Makros verwenden

Makros werden mit TAG-Attributen ähnlich den TAL-Anweisungen definiert. Makro-Tag-Attribute werden als METAL-Anweisungen bezeichnet, wobei METAL für Macro Expansion Tag Attribute Language steht. Das folgende Beispiel zeigt die Definition eines Makros:

        

Copyright 2001, Foo, Bar und Co. KG

Diese metal:define-macro-Anweisung definiert ein Makro namens "copyright", das aus dem Tag p und seinem Inhalt besteht (einschließlich aller darin enthaltenen Tags).

In einer Seitenvorlage definierte Makros werden im Attribut macro der Vorlage gespeichert. Makros aus einer anderen Vorlage können Sie verwenden, indem Sie über das Attribut macros der Seitenvorlage, in der sie definiert sind, auf sie verweisen. Nehmen wir z. B. an, dass das Makro copyright in der Seitenvorlage "master_page" definiert ist. In einer anderen Seitenvorlage wird copyright nun mit dem folgenden Code aufgerufen:

        
Hier folgt das Makro

Wenn Zope diese Seitenvorlage umsetzt, wird das Tag b vollständig durch das Makro ersetzt:

        

Copyright 2001, Foo, Bar und Co. KG

Wird das Makro geändert (z. B. wegen Namensänderung des Urheberrechtsinhabers), so spiegelt sich diese Änderung in allen Seitenvorlagen wider, die dieses Makro verwenden.

Beachten Sie, dass das Makro durch einen Pfadausdruck mit der Anweisung metal:use-macro angegeben wird. Die Anweisung metal:use-macro ersetzt das Anweisungselement durch das genannte Makro.

Makros im Detail

Die Anweisungen metal:define-macro und metal:use-macro sind recht einfach. Allerdings gibt es einige Feinheiten, die erwähnt zu werden verdienen.

Der Name eines Makros muss innerhalb der Seitenvorlage, in der es definiert wird, eindeutig sein. Sie können in einer Vorlage mehrere Makros definieren, doch jedes dieser Makros muss einen anderen Namen haben.

Normalerweise verweist man auf Makros in einer metal:use-macro-Anweisung mit einem Pfadausdruck. Eigentlich kann man aber jeden beliebigen Ausdruckstyp verwenden, wichtig ist nur, dass er ein Makro zurückgibt. Hierzu ein Beispiel:

        

Wird durch ein dynamisch ermitteltes Makro ersetzt, das vom Skript getMacro gesucht wird.

Verweist man mit Python-Ausdrücken auf Makros, so kann man das Makro, das eine Vorlage verwenden soll, dynamisch wechseln.

Das folgende Beispiel veranschaulicht, wie die Anweisung metal:use-macro zusammen mit der Variable default verwendet wird:

        

Dieser Inhalt bleibt erhalten - es wird kein Makro verwendet.

Dieser Code führt zu demselben Ergebnis wie die Verwendung von default mit tal:content und tal:replace; das Anweisungselement bleibt unverändert.

Der Versuch, die Variable nothing mit metal:use-macro zu verwenden, löst einen Fehler aus, da nothing kein Makro ist. Falls Sie nothing verwenden möchten, um ein Makro bedingt einzufügen, sollten Sie stattdessen die Anweisung metal:use-macro in eine tal:condition-Anweisung einschließen.

Bei der Umsetzung von Vorlagen behandelt Zope zuerst Makros und wertet dann TAL-Ausdrücke aus. Betrachten Sie z. B. das folgende Makro:

        

Titel der Vorlage

Dieses Makro fügt den Titel der Vorlage ein, in der das Makro verwendet wird, nicht den der Vorlage, in der es definiert wird. Anders ausgedrückt: Verwendet man ein Makro, so ist das dasselbe, wie wenn man das Makro in eine Vorlage kopiert und diese dann umsetzt.

Wenn Sie die Option Expand macros when editing in der Ansicht Edit einer Seitenvorlage aktivieren, werden alle Makros, die Sie verwenden, im Quellcode der Seitenvorlage vollständig angezeigt. Dies ist das Standardverhalten von Zope und in aller Regel auch das gewünschte Verhalten, da man so eine vollständige und gültige Seite bearbeiten kann. Manchmal ist es jedoch komfortabler, die Makros während der Bearbeitung nicht vollständig anzuzeigen. Dies ist insbesondere dann der Fall, wenn man keinen WYSISYG-Editor verwendet, sondern im ZMI arbeitet. Um Makros nicht vollständig anzuzeigen, deaktiviert man einfach die entsprechende Option.

Slots

Noch nützlicher werden Makros dadurch, dass man ein Makro bei seinem Einsatz teilweise überschreiben kann. Hierfür definieren Sie so genannte Slots im Makro, die Sie dann, wenn Sie die Vorlage verwenden, füllen können. Betrachten Sie z. B. das folgende Makro für eine Seitenleiste:

        

Links

  • Home
  • Produkte
  • Kundendienst
  • Kontakt

Dieses Makro ist an sich zwar gut, ermöglicht aber keine Abweichungen. Möchten Sie nun in der Seitenleiste zusätzliche Informationen bereitstellen, so besteht eine Lösungsmöglichkeit darin, Slots zu definieren:

        

Links

  • Home
  • Produkte
  • Kundendienst
  • Kontakt

Mit diesem Makro können Sie den Slot folgendermaßen füllen:

        

Beachten Sie auch unsere Sonderaktionen.

Wenn Sie diese Vorlage umsetzen, enthält die Seitenleiste die Zusatzinformation, die Sie im Slot bereitstellen:

        

Links

  • Home
  • Produkte
  • Kundendienst
  • Kontakt
Beachten Sie auch unsereSonderaktionen.

Achten Sie darauf, wie das Element span, das den Slot definiert, durch das Element b ersetzt wird, das den Slot füllt.

Anpassung der Standarddarstellung

Normalerweise dienen Slots dafür, eine Standarddarstellung bereitzustellen, die dann angepasst werden kann. Im obigen Beispiel besteht die Definition des Slots einfach aus einem leeren span-Element. Allerdings können Sie in einer Slot-Definition auch eine Standarddarstellung angeben. Betrachten Sie z. B. die folgende Version des Makros für die Seitenleiste:

        

Links

  • Home
  • Produkte
  • Kundendienst
  • Kontakt

Jetzt können alle Bestandteile der Seitenleiste individuell angepasst werden. Sie können den Slot links so ausfüllen, dass die Seitenleisten-Links neu definiert werden. Füllen Sie ihn jedoch nicht aus, so werden in diesem Slot die Standard-Links angezeigt.

Mit demselben Verfahren können Sie auch Slots in Slots definieren und damit die Standarddarstellung durch eine detailliertere Ausführung überschreiben. Hier sehen Sie noch einmal das Makro für die Seitenleiste, wobei diesmal jedoch innerhalb der Slots weitere Slots definiert werden:

        

Links

  • Home
  • Produketes
  • Kundendienst
  • Kontakt

Möchten Sie die Links in der Seitenleiste anpassen, so können Sie entweder den Slot links so füllen, dass er die Links vollständig überschreibt, oder den Slot additional_links so füllen, dass nach den Standard-Links noch weitere Links eingefügt werden. Slots können beliebig tief geschachtelt werden.

METAL und TAL kombinieren

METAL- und TAL-Anweisungen können auf dieselben Elemente angewandt werden:

        
  • Link-Name

Da METAL-Anweisungen vor TAL-Anweisungen ausgewertet werden, gibt es keine Konflikte. Dieses Beispiel ist auch insofern interessant, als es ein Makro ohne Slots anpasst. Das Makro ruft das Skript getLinks auf, um die Links zu ermitteln. Somit können Sie die Links Ihrer Site anpassen, indem Sie das Skript getLinks an verschiedenen Speicherorten Ihrer Web Site anpassen.

Nicht immer ist es einfach, das beste Verfahren für die Anpassung der Darstellung verschiedener Bereiche einer Site zu finden. Im Allgemeinen empfiehlt es sich, Darstellungselemente mit Slots zu überschreiben und dynamischen Inhalt mit Skripten bereitzustellen. In manchen Fällen, wie etwa dem oben gezeigten Link-Beispiel, ist nicht klar, ob es sich bei einem Seitenelement um Inhalt oder Darstellung handelt. Skripte sind in diesem Fall wahrscheinlich die flexiblere Lösung, besonders wenn die Site Link-Inhaltsobjekte enthält.

Eine Seite als Makro

Nicht nur einzelne Darstellungselemente, die von mehreren Seiten verwendet werden, können mit Makros definiert werden, sondern auch ganze Seiten. Ermöglicht wird dies durch Slots. Das folgende Beispiel zeigt ein Makro, das eine ganze Seite definiert:

        
          
            Der Titel
          

          
            

Titel

Dies ist der Rumpf.

Copyright 2001 Fluffy Enterprises

Dieses Makro definiert eine Seite mit drei Slots: headline, body und footer. Achten Sie darauf, dass der Slot headline eine TAL-Anweisung enthält, die den Inhalt der Überschrift dynamisch ermittelt.

Dieses Makro können Sie in Vorlagen für verschiedene Arten von Inhalt oder für verschiedene Teile einer Site verwenden. In einer Vorlage für Nachrichten könnte das Makro zum Beispiel folgendermaßen eingesetzt werden:

       

         

Pressemeldung: Überschrift

Hier folgt die Meldung selbst.

Diese Vorlage definiert den Slot headline neu, und zwar so, dass er den Text "Pressemeldung" enthält und die Methode getHeadline auf dem aktuellen Objekt aufruft. Außerdem definiert sie den Slot body so, dass er die Methode getBody auf dem aktuellen Objekt aufruft.

Dieses Verfahren ist deshalb so leistungsfähig, weil damit bei einer Änderung des Makros page automatisch auch die Vorlage für die Pressemeldung aktualisiert wird. Sie können z. B. den body der Seite in eine Tabelle einfügen und links davon eine Seitenleiste einrichten; die Vorlage für die Pressemeldung verwendet dann automatisch diese neuen Darstellungselemente.

Damit bietet dieses Verfahren weitaus flexiblere Möglichkeiten, das Look&Feel einer Seite zu steuern, als die DTML-Lösung mit standard_html_header und standard_html_footer. Im Wurzelordner von Zope finden Sie eine Seitenvorlage namens standard_template.pt, die ein Seitenmakro mit einem head- und einem body-Slot enthält. Das folgende Beispiel veranschaulicht eine Möglichkeit, dieses Makro in einer Vorlage zu verwenden:

        
          

Titel

Hier folgt der Textkörper.

Das Makro standard_template.pt wird ähnlich verwendet wie andere Seitenmakros. Eine Besonderheit stellt lediglich der Pfad zum Makro dar. Im obigen Beispiel beginnt der Pfad mit here. Dies bedeutet, dass Zope mit Hilfe der Akquisition nach dem Objekt standard_template.pt sucht, wobei es bei dem Objekt zu suchen beginnt, auf das die Vorlage angewandt wird. Dadurch können Sie die Darstellung von Vorlagen anpassen, indem Sie an verschiedenen Speicherorten individuell angepasste standard_template.pt-Objekte erstellen. Dieses Verfahren entspricht also dem Anpassen der Darstellung durch Überschreiben von standard_html_header und standard_html_footer an einzelnen Stellen einer Web Site. Bei standard_template.pt stehen Ihnen allerdings mehr Möglichkeiten zur Verfügung. Sie können den Pfad zum Makro nicht nur mit here beginnen, sondern auch mit root oder container. Beginnt der Pfad mit root, so erhalten Sie immer die Standardvorlage, die sich im Wurzelordner befindet. Beginnt der Pfad mit container, so sucht Zope die Standardvorlage mit Hilfe der Akquisition und beginnt dabei in dem Ordner, in dem die Vorlage definiert ist. Dies erlaubt zwar die Anpassung des Look&Feel von Vorlagen, nicht aber die Anpassung des Look&Feel unterschiedlicher Objekte anhand ihres Speicherorts innerhalb der Site.

Vorlagen zwischenspeichern

Normalerweise werden Seitenvorlagen zwar relativ schnell umgesetzt, manchmal aber nicht schnell genug. Bei Seiten, auf die häufig zugegriffen wird oder bei denen der Seitenaufbau lange dauert, lohnt es sich, eine höhere Geschwindigkeit auf Kosten des dynamischen Verhaltens zu erzielen. Zu erreichen ist dieser Kompromiss durch Puffern, d. h. Zwischenspeichern im Cache. Weitere Informationen zum Puffern finden Sie im Abschnitt "Pufferung zur Leistungssteigerung" in Kapitel 3, "Verwendung grundlegender Zope-Objekte".

Seitenvorlagen können genau wie andere Objekte mit einem Cache-Manager gepuffert werden. Um eine Seitenvorlage zu puffern, müssen Sie sie mit einem Cache-Manager verbinden. Hierfür wählen Sie entweder in der Ansicht Cache der betreffenden Seitenvorlage den Cache-Manager oder in der Ansicht Associate des Cache-Managers die gewünschte Seitenvorlage.

Das folgende Beispiel veranschaulicht das Puffern einer Seitenvorlage. Zuerst erstellen Sie den Python-basierten Skriptnamen long.py mit dem folgenden Inhalt:

      ## Script (Python) "long.py"
      ##
      for i in range(500):
        for j in range(500):
          for k in range(5):
            pass
      return 'Done'

Der Zweck dieses Skript besteht darin, viel Ausführungszeit in Anspruch zu nehmen. Im nächsten Schritt legen Sie eine Seitenvorlage an, die dieses Skript verwendet; zum Beispiel:

      
        
          

results

Wenn Sie sich diese Seite nun ansehen, werden Sie feststellen, dass ihre Umsetzung einige Zeit dauert. Als Nächstes werden wir die Umsetzung durch Pufferung erheblich beschleunigen. Falls Sie noch keinen Ram-Cache-Manager haben, erstellen Sie ihn jetzt, und zwar unbedingt entweder in demselben Ordner, in dem sich auch die Seitenvorlage befindet, oder auf einer höheren Ebene. Gehen Sie zur Ansicht Cache der Seitenvorlage, wählen Sie dort den Ram-Cache-Manager, den Sie gerade erstellt haben, und klicken Sie Save Changes an. Anschließend klicken Sie den Link Cache Settings an, um zu den Konfigurationseinstellungen des Ram-Cache-Managers zu gelangen. In der Standardeinstellung speichert der Cache Objekte für eine Stunde (3600 Sekunden). Diesen Zeitraum sollten Sie an Ihre Anwendung anpassen. Kehren Sie nun zur Seitenvorlage zurück. Nach wie vor dauert es einige Zeit, bis die Vorlage umgesetzt wird. Wenn Sie die Seite nun jedoch erneut laden, wird sie sofort umgesetzt. Sie können die Seite neu laden, so oft Sie möchten; sie wird immer sofort umgesetzt, da die Seite nun im Cache gespeichert ist.

Ändern Sie die Seitenvorlage, so wird sie aus dem Cache entfernt. Wenn Sie sie dann erneut aufrufen, dauert die Umsetzung wieder einige Zeit. Da sie dabei aber im Cache gespeichert wird, wird sie bei allen folgenden Aufrufen wieder schnell aufgebaut.

Das Puffern ist ein einfaches, aber leistungsstarkes Verfahren, um die Leistung zu steigern. Es ist keine Hexerei, steigert die Geschwindigkeit aber beträchtlich. Bei Anwendungen, bei denen die Leistung eine wichtige Rolle spielt, lohnt sich das Puffern auf jeden Fall.

Hilfprogramme für Seitenvorlagen

Zope-Seitenvorlagen sind leistungsstark, aber einfach. Im Gegensatz zu DTML bieten Seitenvorlagen kaum Hilfsmittel für die Stapelung, das Anlegen von Bäumen, Sortieren usw. Die Erfinder der Seitenvorlagen wollten diese einfach halten. Allerdings vermisst man doch einige der integrierten Funktionen, die DTML bietet. Um diese Lücke zu schließen, umfasst Zope Hilfsprogramme, die die Seitenvorlagen verbessern sollen.

Große Informationsmengen stapeln

Wenn ein Anwender eine Datenbank abfragt und Hunderte von Ergebnissen erhält, so ist es häufig sinnvoller, diese Ergebnisse auf mehrere Seiten zu verteilen (z. B. 20 Ergebnisse pro Seite), als alle Ergebnisse auf einer einzigen Seite auszugeben. Das Zerlegen großer Listen in mehrere kleine wird als Stapelung bezeichnet.

Im Gegensatz zu DTML, bei dem die Stapelung direkt in die Programmiersprache integriert ist, unterstützen Seitenvorlagen diese durch ein besonderes Objekt namens Batch, das sich im Hilfsmodul ZTUtils befindet. Weitere Informationen zu dem Python-Modul ZTUtils finden Sie im Anhang B, "API-Referenz".

Das folgende einfache Beispiel zeigt, wie ein Batch-Objekt erstellt wird:

        
  • 0

Dieses Beispiel setzt eine Liste mit 10 Elementen um (in diesem Fall die Zahlen von 0 bis 9). Das Objekt Batch zerschneidet eine lange Liste in Gruppen oder Batches. In diesem Fall teilt es eine aus hundert Elementen bestehende Liste in Gruppen zu je zehn Elementen.

Um eine Gruppe von zehn Elementen anzuzeigen, übergeben Sie eine andere Anfangszahl:

        

    Dieser Batch beginnt mit dem 14. und endet mit dem 23. Element. Anders ausgedrückt: Er zeigt die Zahlen zwischen 13 und 22 an. Beachten Sie, dass das Argument start des Batches der Index des ersten Elementes ist. Indizes beginnen bei 0 zu zählen, nicht bei 1. Der Index 13 ist demnach das 14. Element der Folge. Python verweist mit Indizes auf Listenelemente.

    Arbeitet man mit Batches, so ist es sinnvoll, Navigationselemente in die Seite einzufügen, damit der Anwender von Batch zu Batch wechseln kann. Das folgende vollständige Batch-Beispiel veranschaulicht die Navigation zwischen einzelnen Gruppen.

        
          
            Der Titel
          
          

          

zurück weiter

  • Hans Müller verdient $100.000 im Jahr.

Dieses Beispiel iteriert über Ergebnisgruppen aus der ZSQL-Methode getEmployees. Es zeichnet die Links zurück und weiter, um das Blättern durch die Ergebnisgruppen zu ermöglichen.

Sehen Sie sich die Anweisung tal:define im Element body etwas genauer an. Sie definiert mehrere Batch-Variablen. Die Variable employees ist eine möglicherweise lange Liste von employee-Objekten, die von der ZSQL-Methode getEmployees zurückgegeben wird. Die zweite Variable, start, ist entweder auf den Wert von request/start oder, falls die Anfrage keine start-Variable enthält, auf null gesetzt. Die Variable start verfolgt, an welcher Stelle der Angestelltenliste Sie sich gerade befinden. Die Variable batch ist eine Gruppe von zehn Elementen aus der Angestelltenliste. Die Gruppe beginnt an der von der Variable start angegebenen Position. Die Variablen previous und next verweisen auf die vorhergehende und die folgende Gruppe (soweit vorhanden). Da alle diese Variablen im Element body definiert sind, stehen sie allen Elementen im Body zur Verfügung.

Sehen wir uns nun die Navigations-Links an. Diese erstellen Hyperlinks, die das Blättern zur vorhergehenden und zur folgenden Gruppe ermöglichen. Die Anweisung tal:condition prüft zuerst, ob es eine vorhergehende und eine folgende Gruppe gibt. Ist dies der Fall, so wird der Link dargestellt, anderenfalls nicht. Die Anweisung tal:attributes erstellt einen Link zur vorhergehenden und zur folgenden Gruppe. Der Link besteht einfach aus dem URL der aktuellen Seite ('request/URL0') und einer Anfragezeichenkette, die den Anfangsindex der Gruppe angibt. Beginnt die aktuelle Gruppe zum Beispiel mit dem Index 10, so muss die vorhergehende Gruppe mit dem Index 0 beginnen. Die Variable first einer Gruppe gibt deren Anfangsindex an, in diesem Fall ist previous.start also 0.

Sie brauchen nicht alle Einzelheiten dieses Beispiels zu verstehen. Kopieren Sie es einfach oder verwenden Sie ein vom Z Search Interface erstelltes Stapelungsbeispiel. Wenn Sie später komplexere Batch-Aufgaben lösen möchten, können Sie mit diesem Beispielcode experimentieren. In Anhang B, "API-Referenz" finden Sie weitere Informationen zum Modul ZTUtils sowie zu Batch-Objekten.

Verschiedene Hilfsprogramme

Zope bietet eine Reihe von Python-Modulen, die die Arbeit mit Seitenvorlagen erleichtern. Die Module string, math und random können in Python-Ausdrücken für die Formatierung von Zeichenketten, für mathematische Funktionen und für die Erzeugung von Zufallszahlen verwendet werden. Diese Module stehen in Python-basierten und DTML-Skripten gleichermaßen zur Verfügung. Weitere Informationen dazu finden Sie in Anhang B, "API-Referenz".

Das Modul Products.PythonScripts.standard soll Hilfsprogramme für Python-basierte Skripte bereitstellen, ist aber auch bei der Arbeit mit Seitenvorlagen sinnvoll. Es umfasst verschiedene Funktionen für die Formatierung von Zeichenketten und Zahlen. Weitere Informationen dazu finden Sie in Anhang B, "API-Referenz".

Wie in diesem Kapitel bereits erwähnt wurde, stellt das Modul sequence die nützliche Funktion sort bereit. Einzelheiten dazu finden Sie in Anhang B, "API-Referenz".

Das Modul AccessControl enthält eine Funktion und eine Klasse, die Sie für die Prüfung des Zugriffs sowie für das Abrufen berechtigter Anwender benötigen. Weitere Informationen dazu finden Sie in Anhang B, "API-Referenz".

Zusammenfassung

Dieses Kapitel behandelt die Einzelheiten von Seitenvorlagen, und stiftet zunächst vielleicht vor allem Verwirrung. Aber keine Sorge: Um Seitenvorlagen effizient einzusetzen, brauchen Sie nicht alles zu wissen, was hier angesprochen wurde. Wichtig sind die verschiedenen Pfadtypen und Makros. Die übrigen Informationen, die komplizierteren Aspekte, die Sie in diesem Kapitel kennen gelernt haben, können Sie auch später jeder Zeit nachlesen, wenn Sie sie tatsächlich benötigen. Doch es ist beruhigend, zu wissen, dass Ihnen dann, wenn Sie soweit sind, mit Seitenvorlagen beeindruckende Möglichkeiten offenstehen.

Created by dzugng
Last modified 09.04.2005 15:21

Mitwirkende

Ersteller
   dzugng
Lokal
   vbachs

Seite gerendert in 94ms.