Zope Page Templates: ZPT in Pillole
Note: Return to tutorial view.
Principi di ZPT
Perchè ZPT
Nella costruzione di interfacce utente di tipo XHTML (di un sito, di un'applicazione web generica) spesso devono interagire due diverse figure professionali.
Da un lato abbiamo il designer, che definisce il layout, lo stile e in generale il come vanno presentate all'utente le varie funzioni che gli stiamo fornendo.
Dall'altro abbiamo lo sviluppatore, che alle "pagine" dà vita, collegandole ai dati, alla gestione della sicurezza, e ai servizi che vengono erogati.
Gli strumenti usati dalle due figure sono di tipo diverso, ma per entrambi devono essere capaci di gestire pagine XHTML.
I Principi di Base di ZPT
Zope Page Template cerca di far collaborare sviluppatori e designer sullo stesso file adottando tre princìpi base: vediamoli insieme.
1 - Funzionare con qualsiasi editor XHTML (dreamweaver, textmate, etc.)
Nei linguaggi di templating, di solito, i comandi usati dagli sviluppatori per dare vita alla pagina finale vengono immersi nelle pagine XHTML prodotte dai designer.
Tali comandi, tuttavia, non fanno parte della normale sintassi XHTML. Per questo motivo gli editor dei designer, spesso, non riesco ad aprire i template, dopo che gli sviluppatori ci ha messo mano.
Caso peggiore: quando riescono riescono ad aprire i template manipolati dagli sviluppatori, i designer rovinano facilmente il lavoro fatto, propri perchè l'editor non sa mostrare i comandi aggiunti dagli sviluppatori, che quindi si perdono tra le varie versioni.
ZPT nasce per superare questo problema!
2 - Produrre template fedeli alle pagine finali
Normalmente i designer hanno bisogno di inserire elementi "fantoccio" per valutare l'impatto delle parti che costituiranno la pagina finale, tuttavia tali elementi devono sparire dalla versione renderizzata del template, seppur devono restare nel template, affinchè continui ad essere valido per i designer nel momento in cui dovranno rimetterci mano.
Al contrario, a volte sono gli sviluppatori a dover caricare elementi, utili al template, che però devono essere ignorati dall'editor usato dai designer, pena l'accanimento dei designer nel toglierli di mezzo, tornando a guastare il lavoro degli sviluppatori.
ZPT vuole permettere la creazione di template che siano il più possibile simili alle pagine finali.
3 - Tenere il codice fuori dai template
Questo è un punto valido soprattutto per gli sviluppatori.
Se il linguaggio di templating è troppo potente, gli sviluppatori, per eccessivo "amore di sintesi" (diciamo.. :)), tendono a immergere nel layout del template le logiche (definite a volte "business rules") che dovrebbero essere piuttosto descritte altrove.
ZPT vuole "aiutare" gli sviluppatori a produrre buone applicazioni, e non facilita la generazione di logiche avanzate all'interno dei template:
- Mediante comandi ZPT si possono rimpiazzare interi tag, il loro contenuto, o solo alcuni attributi. Si può ripetere il tag più volte od ometterlo completamente.
- Non si possono creare sottoprocedure o classi, scrivere cicli o test a più vie, o esprimere facilmente algoritmi complessi.
Insomma: la logica deve stare fuori dall'interfaccia!
I Componenti di ZPT
Implementato in Python, Zope Page Template è linguaggio di templating di lungo corso: da lunghi anni sostiene le esigenze più imprevedibili di applicativi versatili e potenti come Plone senza scomporsi.
I principi espressi sopra ispirano l'architettura dei componenti fondamentali della tecnologia ZPT, capace di sfornare pagine XML ben formate (e di conseguenza XHTML).
TAL: Template Attribute Language
L'innovazione principale introdotta dai creatori di ZPT consiste nell'aver spostato i comandi che rendono dinamico il template all'interno dei tag dell'XML, sfruttando un apposito namespace, TAL appunto.
Questo stratagemma da solo ottiene due risultati: fa sì che gli editor XHTML, che normalmente odiano i tag che non conoscono, possano tranquillamente ignorare gli attributi di namespace che non conoscono; inoltre evita che i designer rompano le logiche aggiunte dagli sviluppatori agli elementi visuali, in quanto tali logiche seguono negli spostamenti gli elementi di cui sono attributo.
TALES: TAL Expression Syntax
Per poter aggiungere elementi di programmazione complesse (ma non troppo) si hanno a disposizione una serie di espressioni, capaci di fornire dati alle istruzioni TAL e METAL.
METAL: Macro Expansion TAL
Uno strumento moderno e di prima classe come ZPT non può fare a meno di favorire la modularizzazione e il riutilizzo dei template: METAL è uno strumento di macro preprocessing versatile e potente, degno complemento di TAL e TALES.
TAL: in concreto
ZPT permette di costruire un modello della pagina da generare, che a sua volta risulta HTML valido. Vediamo un semplice esempio:
<title tal:content="here/title">Page Title</title>
L'editor wysiwyg del designer ignorerà la parte dinamica, poiché “tal:” viene interpretato come namespace XML, inoltre farà comparire “Page Title” esattamente nella forma definita dal designer.
Facilmente lo sviluppatore può dinamizzare il mock-up che gli fornisce il designer:
<p> l'url che hai richiesto è: <b>url richiesta</b>. </p>
andando ad aggiungere adeguati attributi tal:
<p> l'url che hai richiesto è: <b tal:content="request/URL">url richiesta</b>. </p>
che nel momento in cui vengono aperti con l'editor wysiwyg del designer mostrano esattamente lo stesso risultato, mentre, quando vengono renderizzati, trasformano come richiesto l'XHTML finale.
TALES: espressioni in ZPT
TALES fornisce vari tipi di espressioni, utili a dare vita ai nostri template.
Path Expression
Le path expression sono il modo di richiamare attributi su specifici oggetti, come nel caso degli esempio seguenti:
- request/URL
- URL della richiesta web corrente.
- user/getUserName
- username dell'utente responsabile della richiesta.
- Container/objectIds
- lista degli Id degli oggetti nella stessa Cartella che contiene il template corrente.
Tali espressioni sono l'equivalente di espressioni Python del tipo: request.URL; user.getUserName(); Container.objectIds()
String Expression
Le string expression sono la via ZPT per formattare stringhe da utilizzare nei template.
Ad esempio, il template seguente:
<b tal:content=”string:titolo: ${here/title}”/>
Dopo il rendering si trasforma in qualcosa di simile a questo:
<b>titolo: doc1</b>
Python Expression
Le Python expression consentono di sfruttare nei template la flessibilità del Python senza ricorrere a script esterni:
Ad esempio il template seguente:
<div tal:replace=”python:here.getSize() / 100”/>px
sarà renderizzato con qualcosa di simile a questo:
240px
Oggetti disponibili in ZPT
La colla che fa funzionare il tutto sono delle parole chiave che possiamo sempre utilizzare nei nostri template. Le più importanti da mandare a memoria sono:
- nothing
- rappresenta un nonvalore (analogo a None, void, Null, ...)
- here
- l'oggetto al quale il template viene “applicato”
- template
- il template stesso
- request
- l'oggetto REQUEST di Zope
- user
- l'oggetto che rappresenta l'utente registrato
TAL in pillole
Inserire Testo
Funzionalità minima richiesta ad un template language, come abbiamo visto, TAL gioca con i tag definendone il contenuto.
Possiamo utilizzare l'istruzione content per definire il contenuto di un tag, ad esempio il template seguente:
<H1 tal:content=”here/title”/>
si trasformerà in qualcosa di simile a questo (dipende dal valore dell'attributo `title` del contesto a cui applichiamo il template!):
<H1>Homepage</H1>
In alternativa possiamo direttamente rimpiazzare un tag usando l'istruzione replace:
<H1 tal:replace=”here/title”>Titolo</H1>
in questo caso otterremo piuttosto:
Homepage
- attenzione a cosa chiedete!!
- ;) il tag H1 è sparito dalla pagina!
Strutture Cicliche
Il vantaggio di un template è quello di potersi fermare alla descrizione di quello che sarà il risultato finale!
TAL offre l'istruzione repeat, con cui velovemente costruire una sequenza di elementi nella pagina usando le informazioni fornite dagli elementi di una lista Python:
Esaminate attentamente il template seguente:
<table border="1" width="100%">
<tr tal:repeat="item container/objectValues">
<td tal:content="repeat/item/number">#</td>
<td tal:content="item/id">Id</td>
<td tal:content="item/title">Title</td>
</tr>
</table>
Con un po' di fantasia vedrete formarsi una tabella, la cui prima colonna riporta il numero della riga corrente!
- NB: se proprio non la vedete
- ..provate ad applicare il template ad una cartella Zope ;))
Condizioni
L'istruzione tal per decidere se far comparire un tag e tutto il suo contenuto nella pagina finale è condition:
<table border="1" width=”100%”
tal:condition="container/objectValues">
<tr tal:repeat="item container/objectValues">
<td tal:content="repeat/item/number">#</td>
<td tal:content="item/id">Id</td>
<td tal:content="item/title">Title</td>
</tr>
</table>
La tal:condition che abbiamo aggiunto nel nostro template controlla che la tabella venga costruita solo se l'espressione tales container/objectValues fornisce effettivamente degli oggetti da elencare.
Definire Variabili
L'istruzione define ci permette di definire delle variabili valide all'interno del tag in cui vengono definite:
<table border="1" width=”100%”
tal:define="object_list container/objectValues"
tal:condition="object_list">
<tr tal:repeat="item object_list">
<td tal:content="repeat/item/number">#</td>
<td tal:content="item/id">Id</td>
<td tal:content="item/title">Title</td>
</tr>
</table>
Nel precedente template, object_list potrà essere utilizzato ovunque nel contesto del tag table.
Gli Attributi dei Tag
Per poter costruire dinamicamente gli attributi dei tag dei nostri template, tal ci fornisce l'istruzione attributes:
<td>
<img src=”/images/icon.png”
tal:attributes="src item/icon"/>
<span tal:replace="item/meta_type">MType</span>
</td>
Nel template precedente, l'editor wysiwyg del designer caricherà l'immagine icon.gif nella cartella /images, mentre, dopo il rendering, il valore dell'attributo src sarà sostituito dal risultato dell'espressione item/icon.
Structure e omit-tag
Le istruzioni tal:content e tal:replace quotano il testo che inseriscono nel template renderizzato: ad esempio < sostituisce il carattere <.
Nei casi in cui vogliamo evitarlo, perchè stiamo effettivamente inserendo degli elementi XHTML ben formati, è sufficiente usare la direttiva structure.
Se invece avete bisogno di togliere di mezzo un tag inserito dal designer, ma mantenendo in uscita il suo contenuto, potete usare l'istruzione òmit-tag:
<div tal:define="ciao string:<b>ciao</b>"
tal:omittag="nothing">
<span tal:replace="ciao"/>
<span tal:replace="structure ciao"/>
</div>
Il template precedente dopo il rendering produce il risultato seguente:
<b>ciao<b> <b>ciao</b>
Dovrebbe essere abbastanza facile immaginare come un browser web vi mostrerà il risultato. :)
Tag fantasma: nothing
Editare un template in un editor wysiwyg è poco utile se non si utilizzano dei segnaposto, che devono però scomparire a runtime.
Se ad esempio il designer prevede di inserire una tabella in un certo punto, avrà bisogno di caricarci dei record per capire come impattano sulla pagina.
Lo sviluppatore non vuole mostrare quei record agli utenti finali della pagine, ma dovrà fare lasciarli disponibili al designer. Per farlo gli sarà sufficiente usare un'istruzione replace con valore nothing:
<tr tal:replace="nothing"> <td>nome</td> <td>cognome</td> </tr>
Tutto questo template non produce nulla in fase di rendering, ma il designer potrà vedere nel suo editor alcune righe della tabella per capire il loro impatto sulla pagina.
Gestione Errori
L'istruzione on-error permette di gestire errori all'interno dei template.
Considerate il template seguente:
<b tal:onerror="string:username non definito"
tal:content="here/getUsername">Mauro</b>
Se l'espressione here/getUsername restituisce errore, dopo il rendering avremo:
<b>username non definito</b>
Analogamente, nel caso del seguente template:
<b tal:onerror="nothing"
tal:content="here/getUsername">Mauro</b>
Se l'espressione here/getUsername restituisce errore in fase di rendering l'intero tag verrà eliminato.
...E non Finisce Qui!
Molto altro dovrebbe essere detto sulle possibilità offerte da TAL, ma non è più tempo...
Lo ZopeBook - http://docs.zope.org/ - offre due interi capitoli su ZPT oltre alla ZPT reference.
Sul Plone.org c'è un valido tutorial di Limi: http://plone.org/documentation/tutorial/zpt.
Inotre, come al solito, molti validi spunti ed esempi sono sparsi nella rete: Google è il vostro migliore amico!
METAL: macro e slot
Zope è incentrato sugli oggetti e sul concetto di riusabilità del codice: 'riusare' significa fare il massimo col minimo, ridurre gli errori e i tempi di manutenzione delle applicazioni.
Una applicazione web mostra di solito un'interfaccia piuttosto ricca, ma basata su elementi ricorrenti: METAL offre la tecnologia necessaria a poter definire e richiamare tali elementi nei vari template che costituiscono la nostra interfaccia utente.
Le Macro
Una macro è una sezione di un template definita in modo da poter essere richiamata in altri template:
<p metal:definemacro="copyright">
Copyright 2001,
<em tal:content="here/author">
Zope.it</em>
</p>
Richiamando la macro copyright di questo template in un determinato punto di un altro template, si avrà l'espansione della macro in quel punto, come se in quel punto fosse definita.
Immaginiamo che il template precedente abbia il nome 'master'. La sua macro 'copyright' potrà essere richiamata dovunque se ne abbia bisogno:
<b metal:usemacro="container/master/macros/copyright">
Qui sarà espansa la macro
</b>
Questo secondo template avrà come risultato dopo il rendering qualcosa di simile a questo:
<p>
Copyright 2001,
<em>m.delmonte</em>
</p>
- NOTA!!
- guardate bene, il tag (b nel nostro caso) viene completamente sostituito, come se l'espansione della macro fosse applicata con un'istruzione replace.
Gli Slot
Uno slot è una sezione di una macro definita in modo da essere riempita nel momento in cui la macro viene espansa dal template che la richiama:
<div metal:definemacro="sidebar">
<h1>Links</h1>
<ul metal:defineslot="links">
<li>non ci sono link da mostrare.</li>
</ul>
</div>
In questo modo è possibile marcare all'interno della macro delle sezioni modificabili da parte del template che le utilizza.
Considerate che la macro precedente sia contenuta in un template chiamato 'doc1'. Un template che la richiama potrà usare lo slot per inserire i link che desidera come segue:
<div metal:usemacro="here/doc1/macros/sidebar">
<ul metal:fillslot="links">
<li><a href="http://linux.org”>Linux</a></li>
<li><a href="http://zope.org”>Zope</a></li>
</ul>
<div>
Nel momento in cui il template viene renderizzato si ottiene:
<h1>Links</h1> <ul> <li><a href="http://linux.org">Linux</a></li> <li><a href="http://zope.org">Zope</a></li> </ul>
Bene, non resta che augurarvi buon divertimento!
