Become a member!

TemplatePro - Documentazione Ufficiale

Aggiornato il 25-11-2025 alla versione 0.8.0 del linguaggio TemplatePro.

Ecco un esempio di applicazione web dinamica realizzata con DMVCFramework, TemplatePro e HTMX.

TemplatePro è un motore di templating moderno e versatile progettato per semplificare la generazione dinamica di HTML, contenuti email e file di testo. Con una sintassi ispirata a sistemi di templating popolari come Jinja e Smarty, TemplatePro offre funzionalità potenti tra cui blocchi condizionali, cicli, ereditarietà dei template, macro riutilizzabili e supporto per dati JSON.

La documentazione per le versioni precedenti alla 0.8.0 è disponibile qui.

Questo articolo è disponibile anche in inglese.

Dalla versione 0.7.0 TemplatePro è case insensitive sia nei nomi delle variabili che nelle direttive.

Quick Start

Il modo più semplice per usare TemplatePro: compila una stringa template, imposta le variabili e genera l’output.

var
  lCompiler: TTProCompiler;
  lCompiledTemplate: ITProCompiledTemplate;
begin
  lCompiler := TTProCompiler.Create();
  try
    lCompiledTemplate := lCompiler.Compile('Ciao {{:name}}! Hai {{:age}} anni.');
  finally
    lCompiler.Free;
  end;

  lCompiledTemplate.SetData('name', 'Daniele');
  lCompiledTemplate.SetData('age', 50);
  WriteLn(lCompiledTemplate.Render);
end;

Output:

Ciao Daniele! Hai 50 anni.

Tutto qui! Compila un template, imposta alcune variabili e genera l’output. Ora esploriamo tutte le funzionalità che TemplatePro offre.

Esempio Completo

Per scenari reali, spesso avrai bisogno di filtri per trasformare i dati e funzioni personalizzate per esigenze di formattazione specifiche.

program tproconsole;

{$APPTYPE CONSOLE}

uses
  TemplatePro,
  System.Rtti,
  System.SysUtils;

// Filtro personalizzato che racchiude il testo tra parentesi quadre
function AddSquareBrackets(
  const aValue: TValue;
  const aParameters: TArray<TFilterParameter>): TValue;
begin
  Result := '[' + aValue.AsString + ']';
end;

var
  lCompiler: TTProCompiler;
  lCompiledTemplate: ITProCompiledTemplate;
begin
  lCompiler := TTProCompiler.Create();
  try
    lCompiledTemplate := lCompiler.Compile(
      'Ciao {{:name|brackets}}! Oggi è {{:today|datetostr}}.');
  finally
    lCompiler.Free;
  end;

  lCompiledTemplate.SetData('name', 'Daniele Teti');
  lCompiledTemplate.SetData('today', Date);
  lCompiledTemplate.AddFilter('brackets', AddSquareBrackets);

  WriteLn(lCompiledTemplate.Render);
  // Output: Ciao [Daniele Teti]! Oggi è 2025-11-25.
end.

Per migliori prestazioni di avvio in produzione, salva e ricarica i template compilati da disco:

// Salva il template compilato su file
lCompiledTemplate.SaveToFile('template.tpc');

// Carica un template pre-compilato (deve essere la stessa versione di TemplatePro)
lCompiledTemplate := TTProCompiledTemplate.CreateFromFile('template.tpc');

1. Interpolazione delle Variabili

Usa la sintassi {{:variable}} per iniettare contenuto dinamico nei template.

Variabili Semplici

Visualizza valori base come stringhe, numeri o date direttamente nell’output:

Ciao, {{:name}}!
Hai {{:age}} anni.

Accesso alle Proprietà degli Oggetti

Quando lavori con oggetti Delphi, accedi alle proprietà annidate usando la notazione con punto:

{{:user.profile.first_name}} {{:user.profile.last_name}}
Email: {{:user.contact.email}}

Accesso agli Elementi di un Array

Per dati di tipo array o lista, usa la notazione con parentesi quadre con indici a base zero:

Primo elemento: {{:items[0]}}
Secondo elemento: {{:items[1]}}

Variabili Null o Non Definite

Le variabili mancanti o null vengono renderizzate come stringhe vuote, evitando errori a runtime:

Questo sarà vuoto se non definito: {{:undefined_var}}

2. Logica Condizionale con if/else

Controlla quale contenuto appare in base alle condizioni sui dati.

Blocchi Condizionali Base

Mostra contenuto diverso agli utenti loggati rispetto agli anonimi:

{{if user_logged_in}}
  Bentornato, {{:username}}!
{{else}}
  Effettua il login per continuare.
{{endif}}

Valutazione della Veridicità

TemplatePro valuta i diversi tipi di dato per la loro veridicità:

  • Stringhe: le stringhe vuote sono false, le stringhe non vuote sono vere
  • Numeri: lo zero è falso, i numeri diversi da zero sono veri
  • Oggetti: gli oggetti null sono falsi, gli oggetti non null sono veri
  • Collezioni: le collezioni/dataset vuoti sono falsi, quelli non vuoti sono veri
  • Booleani: i valori true/false funzionano come previsto

Espressioni Condizionali con Filtri

Usa filtri di confronto per implementare logica di business come verifica dell’età o validazione input:

{{if age|ge,18}}
  Sei maggiorenne.
{{else}}
  Sei minorenne.
{{endif}}

{{if username|contains,"admin"}}
  Utente amministratore rilevato.
{{endif}}

{{if password|eq,confirm_password}}
  Le password corrispondono.
{{else}}
  Conferma password fallita.
{{endif}}

Filtri Logici and e or

Combina più condizioni per scenari di validazione complessi:

{{if value1|and,value2}}
  Entrambi sono veri
{{else}}
  Almeno uno è falso
{{endif}}

{{if value1|or,value2}}
  Almeno uno è vero
{{else}}
  Entrambi sono falsi
{{endif}}

Questi filtri sono utili per verificare più requisiti contemporaneamente:

{{if user.active|and,user.verified}}
  Account completamente attivo
{{endif}}

{{if email_error|or,password_error}}
  Ci sono errori nel form
{{endif}}

3. Cicli con for .. in

Itera sulle collezioni per generare contenuto ripetuto come liste, tabelle o card.

Struttura Base

Renderizza una semplice lista di persone da una collezione:

{{for person in people}}
  - {{:person.first_name}} {{:person.last_name}}
{{endfor}}

Controllo del Ciclo con continue

Salta certi elementi in base a condizioni, come filtrare prodotti fuori produzione:

{{for product in products}}
  {{if product.discontinued|eq,true}}
    {{continue}}
  {{endif}}
  Prodotto: {{:product.name}} - Prezzo: {{:product.price}}
{{endfor}}

Cicli Annidati

Visualizza dati gerarchici come contatti con più numeri di telefono:

{{for person in people}}
  {{:person.first_name}} {{:person.last_name}}
  {{for phone in person.phones}}
    - {{:phone.type}}: {{:phone.number}}
  {{endfor}}
{{endfor}}

Pseudo-Variabili nei Cicli

Usa le variabili di ciclo incorporate per numerazione, striping zebrato o stili alternati:

  • @@index: indice dell’iterazione corrente (a base 1)
  • @@odd: vero per gli elementi con indice dispari
  • @@even: vero per gli elementi con indice pari
{{for customer in customers}}
{{:customer.@@index}}. {{:customer.Name}}
{{if customer.@@odd}}
  (Posizione dispari)
{{endif}}
{{if customer.@@even}}
  (Posizione pari)
{{endif}}
{{endfor}}

4. Dataset

Renderizza record TDataSet di Delphi direttamente nei template per applicazioni database-driven:

{{if customers}}
  <table>
    <tr><th>Codice</th><th>Nome</th><th>Città</th></tr>
    {{for customer in customers}}
      <tr>
        <td>{{:customer.Code}}</td>
        <td>{{:customer.Name}}</td>
        <td>{{:customer.City}}</td>
      </tr>
    {{endfor}}
  </table>
{{else}}
  <p>Nessun cliente nel database.</p>
{{endif}}

5. Filtri Built-in

Trasforma i valori in output usando la sintassi pipe {{:value|filter}}.

Filtri di Trasformazione Testo

Cambia il case del testo per requisiti di visualizzazione o formattazione consistente:

Originale: {{:name}}
Maiuscolo: {{:name|uppercase}}
Minuscolo: {{:name|lowercase}}
Capitalizzato: {{:name|capitalize}}

Filtri di Padding

Allinea il testo in output a larghezza fissa come report o applicazioni console:

Padding a destra: "{{:code|rpad,10}}"
Padding a destra con trattini: "{{:code|rpad,10,"-"}}"
Padding a sinistra: "{{:code|lpad,8}}"
Padding a sinistra con zeri: "{{:id|lpad,6,"0"}}"

Filtri Data e Ora

Formatta le date per diverse localizzazioni o requisiti di visualizzazione:

Formato sistema: {{:birth_date|datetostr}}
Formato personalizzato: {{:birth_date|datetostr,"dd/mm/yyyy"}}
DateTime: {{:created_at|datetimetostr,"yyyy-mm-dd hh:nn:ss"}}
Formato ISO: {{:timestamp|datetoiso8601}}

Filtri Numerici

Visualizza numeri con simboli di valuta, decimali o formati percentuale:

Formattato: {{:price|formatfloat,"$#,##0.00"}}
Percentuale: {{:rate|formatfloat,"0.00%"}}

Filtri di Elaborazione Testo

Tronca testo lungo o escapa caratteri HTML per sicurezza:

Troncato: {{:description|trunc,50}}
HTML encoded: {{:user_input|htmlencode}}
Versione: {{:""|version}}

Il Filtro default

Fornisce valori di fallback per dati vuoti, null o zero per evitare output vuoti:

Valore con contenuto: {{:value|default,"fallback"}}
Valore vuoto/zero: {{:zero_value|default,"N/A"}}
Default numerico: {{:quantity|default,1}}

Concatena default per fallback multi-livello:

Benvenuto, {{:nickname|default,name|default,"Ospite"}}!
Quantità: {{:qty|default,1}}

Riferimento Completo Filtri Built-in

Filtro Descrizione Esempio
uppercase Converte in maiuscolo {{:name|uppercase}}
lowercase Converte in minuscolo {{:name|lowercase}}
capitalize Capitalizza ogni parola {{:title|capitalize}}
rpad,length[,char] Padding a destra fino alla lunghezza {{:code|rpad,10,"-"}}
lpad,length[,char] Padding a sinistra fino alla lunghezza {{:id|lpad,6,"0"}}
datetostr[,format] Formatta data {{:date|datetostr,"dd/mm/yyyy"}}
datetimetostr[,format] Formatta datetime {{:datetime|datetimetostr}}
datetoiso8601 Formato ISO 8601 {{:date|datetoiso8601}}
formatfloat,format Formatta numeri {{:price|formatfloat,"$0.00"}}
trunc,length Tronca testo {{:text|trunc,50}}
htmlencode Codifica HTML {{:input|htmlencode}}
default,value Valore di fallback {{:var|default,"N/A"}}
version Versione TemplatePro {{:|version}}
totrue Sempre vero {{:var|totrue}}
tofalse Sempre falso {{:var|tofalse}}
Filtri di Confronto
eq,value Uguale a {{if age|eq,25}}
ne,value Diverso da {{if status|ne,"inactive"}}
gt,value Maggiore di {{if score|gt,80}}
ge,value Maggiore o uguale {{if age|ge,18}}
lt,value Minore di {{if price|lt,100}}
le,value Minore o uguale {{if items|le,10}}
contains,text Contiene testo {{if name|contains,"John"}}
icontains,text Contiene (case-insensitive) {{if email|icontains,"gmail"}}
Filtri Logici
and,variable AND logico {{if a|and,b}}
or,variable OR logico {{if a|or,b}}

6. Filtri Concatenati

Applica trasformazioni multiple in sequenza - l’output di ogni filtro alimenta il successivo.

Sintassi

{{:variable|filter1|filter2|filter3}}

Esempi Pratici

Normalizza testo, combina operazioni di padding o proteggi input utente con trasformazioni multiple:

{{:name|lowercase|capitalize}}
{{:code|lpad,5|rpad,10}}
{{:description|trunc,50|htmlencode}}

Nel primo esempio, il valore viene prima convertito in minuscolo, poi capitalizzato. Nel secondo, viene applicato prima il padding a sinistra fino a 5 caratteri, poi il padding a destra fino a 10 caratteri totali.

Casi d’Uso Comuni

Costruisci pipeline di formattazione complesse per codici prodotto, contenuti generati dagli utenti o normalizzazione dati:

Formattazione complessa: {{:product_code|uppercase|lpad,10,"0"}}
Sicurezza output: {{:user_input|trunc,100|htmlencode}}
Normalizzazione: {{:email|lowercase|default,"noemail@example.com"}}

I filtri concatenati sono particolarmente utili per:

  • Applicare trasformazioni multiple in modo leggibile
  • Creare pipeline di elaborazione dati
  • Combinare formattazione e sicurezza

7. Filtri Personalizzati

Estendi TemplatePro con le tue funzioni di trasformazione.

Signature delle Funzioni Filtro

Definisci filtri come funzioni regolari o metodi anonimi:

// Funzione regolare
TTProTemplateFunction =
  function(const aValue: TValue; const aParameters: TArray<TFilterParameter>): TValue;

// Metodo anonimo
TTProTemplateAnonFunction =
  reference to function(const aValue: TValue; const aParameters: TArray<TFilterParameter>): TValue;

Esempio di Filtro Personalizzato Semplice

Crea un filtro che racchiude il testo tra parentesi quadre per evidenziarlo:

function AddSquareBrackets(const aValue: TValue;
  const aParameters: TArray<TFilterParameter>): TValue;
begin
  Result := '[' + aValue.AsString + ']';
end;

// Registra il filtro
lCompiledTemplate.AddFilter('brackets', AddSquareBrackets);

Utilizzo:

Originale: {{:username}}
Con parentesi: {{:username|brackets}}

Filtro con Parametri

Crea un filtro configurabile che ripete il testo un numero specificato di volte:

function RepeatText(const aValue: TValue;
  const aParameters: TArray<TFilterParameter>): TValue;
var
  lText: string;
  lCount, i: Integer;
begin
  lText := aValue.AsString;
  lCount := aParameters[0].ParIntValue;
  Result := '';
  for i := 1 to lCount do
    Result := Result + lText;
end;

lCompiledTemplate.AddFilter('repeat', RepeatText);

Utilizzo:

Ripetuto: {{:char|repeat,5}}

Variabili come Parametri dei Filtri

Passa valori dinamici ai filtri per formattazione flessibile guidata dai dati:

{{:message|truncate,max_length}}
{{:price|formatfloat,number_format}}
{{if score|gt,passing_grade}}
  Congratulazioni!
{{endif}}

8. Macro

Definisci blocchi di template riutilizzabili per evitare ripetizioni e mantenere consistenza.

Definizione Base e Chiamata

Crea una macro di saluto semplice che può essere chiamata con nomi diversi:

{{macro greeting(name)}}
Hello, {{:name}}!
{{endmacro}}

{{call greeting("World")}}
{{call greeting("TemplatePro")}}

Output:

Hello, World!
Hello, TemplatePro!

Macro con Parametri Multipli

Costruisci componenti UI riutilizzabili come card che accettano valori multipli:

{{macro card(title, content)}}
<div class="card">
  <h3>{{:title}}</h3>
  <p>{{:content}}</p>
</div>
{{endmacro}}

{{call card("Benvenuto", "Questo è il contenuto")}}
{{call card("Seconda Card", "Altro contenuto qui")}}

Macro senza Parametri

Crea separatori visivi semplici o elementi decorativi:

{{macro separator()}}
---
{{endmacro}}

Inizio
{{call separator()}}
Centro
{{call separator()}}
Fine

Macro con Filtri

Applica trasformazioni all’interno delle macro per output formattato:

{{macro format(text)}}
[{{:text|uppercase}}]
{{endmacro}}

{{call format("hello")}}
{{call format(user_name)}}

Macro con Logica Condizionale

Crea componenti adattivi che cambiano comportamento in base ai parametri:

{{macro greeting(name, formal)}}
{{if formal}}
Buongiorno, Sig. {{:name}}.
{{else}}
Ciao {{:name}}!
{{endif}}
{{endmacro}}

{{call greeting("Rossi", true)}}
{{call greeting("Marco", false)}}

Macro Annidate

Componi componenti complessi facendo chiamare altre macro alle macro:

{{macro inner(text)}}
*{{:text}}*
{{endmacro}}

{{macro outer(text)}}
[{{call inner(text)}}]
{{endmacro}}

{{call outer("nested")}}

Output:

[*nested*]

Macro nei Cicli

Combina macro con cicli per renderizzazione consistente degli elementi:

{{macro item(name, value)}}
- {{:name}}: {{:value}}
{{endmacro}}

{{for obj in objects}}
{{call item(obj.Name, obj.Value)}}
{{endfor}}

Passare Variabili alle Macro

Mescola valori letterali e variabili dinamiche nelle chiamate alle macro:

{{macro showValue(label, value)}}
{{:label}}: {{:value}}
{{endmacro}}

{{call showValue("Nome", "Mario")}}
{{call showValue("Titolo", page_title)}}

9. Funzioni Template

Le funzioni sono filtri applicati a valori vuoti - utili per generare contenuto dinamico senza input.

Ottieni la versione corrente di TemplatePro:

Versione corrente: {{:|version}}

Esempio di Funzione Personalizzata

Crea una funzione generatore di UUID per identificatori univoci:

function GenerateUUID(const aValue: TValue;
  const aParameters: TArray<TFilterParameter>): TValue;
begin
  if not aValue.IsEmpty then
    raise ETProRenderException.Create('"GenerateUUID" è una funzione, non un filtro');
  Result := TGuid.NewGuid.ToString;
end;

lCompiledTemplate.AddFilter('uuid', GenerateUUID);

Utilizzo:

Nuovo ID: {{:|uuid}}

10. Dati JSON

Renderizza strutture JSON annidate complesse con cicli e condizionali:

{{for person in people}}
  {{:person.@@index}}) {{:person.first_name|uppercase}} {{:person.last_name|uppercase}}
  Età: {{:person.age}}

  {{if person.devices}}
    Dispositivi:
    {{for device in person.devices}}
      {{:device.@@index}}. {{:device.name}} ({{:device.type}})
    {{endfor}}
  {{endif}}
{{endfor}}

11. Ereditarietà dei Template

Costruisci layout di pagina consistenti estendendo un template base con blocchi personalizzati.

Template Base (base.tpro)

Definisci la struttura comune con blocchi sostituibili:

<!DOCTYPE html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <title>{{block "title"}}Titolo Default{{endblock}}</title>
    {{block "extra_css"}}{{endblock}}
</head>
<body>
    <header>
        {{block "navigation"}}
            <nav>Menu default</nav>
        {{endblock}}
    </header>

    <main>
        {{block "content"}}
            <p>Contenuto default.</p>
        {{endblock}}
    </main>

    <footer>
        {{block "footer"}}
            <p>Footer default</p>
        {{endblock}}
    </footer>

    {{block "extra_js"}}{{endblock}}
</body>
</html>

Template Figlio

Sovrascrivi blocchi specifici ereditando il resto:

{{extends "base.tpro"}}

{{block "title"}}{{:page_title}} - Il Mio Sito{{endblock}}

{{block "content"}}
    <h1>{{:page_title}}</h1>
    <p>{{:content}}</p>
{{endblock}}

{{block "extra_js"}}
    <script src="/js/page.js"></script>
{{endblock}}

Regole di Ereditarietà

  1. Ereditarietà a singolo livello: i template figli possono estendere solo un template padre
  2. Override dei blocchi: se un figlio definisce un blocco esistente, sovrascrive quello del padre
  3. Blocchi default: se un figlio non definisce un blocco, viene usato il contenuto default del padre
  4. Contenuto ignorato: qualsiasi contenuto fuori dai blocchi nei template figli viene ignorato

12. Inclusione di Template

Dividi i template in file riutilizzabili per header, footer e componenti condivisi:

{{include "header.tpro"}}

<main>
    <h1>{{:page_title}}</h1>
    <p>{{:content}}</p>
</main>

{{include "footer.tpro"}}

Inclusione con Sottodirectory

Organizza i template in cartelle per una migliore manutenibilità:

{{include "partials/navigation.tpro"}}
{{include "components/product-card.tpro"}}

13. Tipi Nullable

Gestisci valori opzionali con controlli condizionali:

{{if user.middle_name}}
    Nome completo: {{:user.first_name}} {{:user.middle_name}} {{:user.last_name}}
{{else}}
    Nome: {{:user.first_name}} {{:user.last_name}}
{{endif}}

{{if order.shipped_date}}
    Spedito: {{:order.shipped_date|datetostr}}
{{else}}
    Stato: In elaborazione
{{endif}}

14. Best Practice e Performance

Compilazione dei Template

  • Compila i template una volta e riutilizza la versione compilata
  • Salva i template compilati su file per migliori prestazioni di avvio
  • Usa strategie di caching appropriate per ambienti di produzione

Uso dei Filtri

  • Usa i filtri built-in quando possibile (sono ottimizzati)
  • Minimizza filtri personalizzati complessi nei cicli
  • Considera di pre-elaborare i dati invece di logica template complessa

Organizzazione dei Template

  • Usa l’ereditarietà per layout consistenti
  • Dividi template grandi in componenti più piccoli e riutilizzabili
  • Organizza i template in strutture di directory logiche
  • Usa le macro per componenti ripetuti

Gestione degli Errori

Racchiudi le operazioni sui template in blocchi try-except per gestire errori di compilazione e rendering:

try
  lCompiledTemplate := lCompiler.Compile(lTemplate);
  lResult := lCompiledTemplate.Render;
except
  on E: ETProCompilerException do
    // Gestisci errori di compilazione
    ShowMessage('Errore di compilazione template: ' + E.Message);
  on E: ETProRenderException do
    // Gestisci errori di rendering
    ShowMessage('Errore di rendering template: ' + E.Message);
  on E: Exception do
    // Gestisci altri errori
    ShowMessage('Errore inaspettato: ' + E.Message);
end;

Conclusione

TemplatePro è un motore di templating completo e potente che fornisce agli sviluppatori la flessibilità e il controllo necessari per lo sviluppo di applicazioni moderne. Le sue caratteristiche principali includono:

  • Sintassi Intuitiva: sintassi pulita e leggibile ispirata a motori popolari
  • Logica Potente: istruzioni condizionali e costrutti di ciclo completi
  • Ereditarietà dei Template: layout riutilizzabili e gerarchie di componenti
  • Macro: blocchi di codice riutilizzabili con parametri
  • Filtri Concatenati: pipeline flessibili di trasformazione dati
  • Filtri Estesi: ricco set di filtri built-in più supporto per filtri personalizzati
  • Eccellenza JSON: supporto di prima classe per strutture dati JSON complesse
  • Type Safety: eccellente gestione del sistema di tipi Delphi inclusi i nullable
  • Design Modulare: inclusione template e sviluppo basato su componenti

Che tu stia costruendo semplici email HTML, applicazioni web complesse o sistemi di generazione report dinamici, TemplatePro fornisce gli strumenti necessari per creare template manutenibili, efficienti e potenti.

Versione Corrente: 0.8.0 - Aggiornato Novembre 2025

Comments

comments powered by Disqus