Template
I pacchetti template di Go
Go include due pacchetti per i template: text/template per il testo generico e html/template per l’HTML con protezione automatica contro le iniezioni XSS. La sintassi e identica, ma html/template effettua l’escaping automatico dei dati inseriti nell’HTML.
Sintassi base: {{ }}
Le azioni nei template sono racchiuse tra doppie parentesi graffe. Il punto (.) rappresenta il dato corrente passato al template:
package main
import (
"os"
"text/template"
)
func main() {
// Template semplice con il punto
tmpl := template.Must(template.New("saluto").Parse(
"Ciao, {{.}}! Benvenuto.\n",
))
tmpl.Execute(os.Stdout, "Mario") // Ciao, Mario! Benvenuto.
// Template con struct
type Persona struct {
Nome string
Eta int
}
tmpl2 := template.Must(template.New("persona").Parse(
"{{.Nome}} ha {{.Eta}} anni.\n",
))
tmpl2.Execute(os.Stdout, Persona{Nome: "Luigi", Eta: 25})
}
Azioni e pipeline
Le azioni sono comandi all’interno di {{ }}. Le pipeline collegano piu comandi con il simbolo |:
package main
import (
"os"
"text/template"
)
func main() {
tmpl := template.Must(template.New("pipeline").Parse(`
Messaggio: {{.Testo}}
Maiuscolo: {{.Testo | printf "%q"}}
Lunghezza: {{.Testo | len}}
`))
dati := struct {
Testo string
}{
Testo: "Ciao dal template",
}
tmpl.Execute(os.Stdout, dati)
}
Le funzioni built-in includono print, printf, println, len, index, html, js, urlquery e molte altre.
Variabili nei template
Possiamo dichiarare e usare variabili nei template con la sintassi $nome:
package main
import (
"os"
"text/template"
)
func main() {
tmpl := template.Must(template.New("variabili").Parse(`
{{$nome := .Nome}}
{{$citta := .Citta}}
L'utente {{$nome}} vive a {{$citta}}.
Il suo indirizzo completo e: {{$nome}}, {{$citta}}, {{.Paese}}.
`))
dati := map[string]string{
"Nome": "Anna",
"Citta": "Roma",
"Paese": "Italia",
}
tmpl.Execute(os.Stdout, dati)
}
Range: iterare su collezioni
L’azione range permette di iterare su slice, array e map:
package main
import (
"os"
"text/template"
)
type Prodotto struct {
Nome string
Prezzo float64
}
func main() {
tmpl := template.Must(template.New("lista").Parse(`
Lista della spesa:
{{range .Prodotti}}- {{.Nome}}: {{printf "%.2f" .Prezzo}} EUR
{{end}}
Totale prodotti: {{len .Prodotti}}
Con indice:
{{range $i, $p := .Prodotti}} {{$i}}. {{$p.Nome}} ({{printf "%.2f" $p.Prezzo}} EUR)
{{end}}
Messaggio se vuoto:
{{range .Vuoto}}Ha elementi{{else}}La lista e vuota{{end}}
`))
dati := struct {
Prodotti []Prodotto
Vuoto []string
}{
Prodotti: []Prodotto{
{"Pane", 1.50},
{"Latte", 1.80},
{"Pasta", 0.90},
},
Vuoto: nil,
}
tmpl.Execute(os.Stdout, dati)
}
If: condizioni nei template
L’azione if permette di controllare il flusso in base a condizioni:
package main
import (
"os"
"text/template"
)
type Utente struct {
Nome string
Premium bool
Eta int
Bio string
}
func main() {
tmpl := template.Must(template.New("condizioni").Parse(`
Utente: {{.Nome}}
{{if .Premium}}Account Premium attivo!{{else}}Account Standard{{end}}
{{if .Bio}}Bio: {{.Bio}}
{{else}}Nessuna bio disponibile
{{end}}
{{if gt .Eta 18}}Utente maggiorenne{{else}}Utente minorenne{{end}}
`))
utente := Utente{
Nome: "Giulia",
Premium: true,
Eta: 22,
Bio: "",
}
tmpl.Execute(os.Stdout, utente)
}
Le funzioni di confronto disponibili sono: eq (==), ne (!=), lt (<), le (<=), gt (>), ge (>=).
Funzioni personalizzate
Possiamo registrare funzioni personalizzate da usare nei template:
package main
import (
"os"
"strings"
"text/template"
"time"
)
func main() {
funzioni := template.FuncMap{
"maiuscolo": strings.ToUpper,
"ripeti": strings.Repeat,
"ora": func() string { return time.Now().Format("15:04:05") },
"somma": func(a, b int) int { return a + b },
}
tmpl := template.Must(
template.New("funzioni").Funcs(funzioni).Parse(`
Nome: {{.Nome | maiuscolo}}
Decorazione: {{ripeti "=" 30}}
Ora corrente: {{ora}}
Somma: {{somma 10 20}}
`))
dati := struct {
Nome string
}{Nome: "Mario"}
tmpl.Execute(os.Stdout, dati)
}
Importante: le funzioni devono essere registrate con Funcs() prima di chiamare Parse().
Template annidati
I template possono includere altri template con define e template:
package main
import (
"os"
"text/template"
)
func main() {
tmpl := template.Must(template.New("pagina").Parse(`
{{define "header"}}
=============================
{{.Titolo}}
=============================
{{end}}
{{define "footer"}}
-----------------------------
(c) {{.Anno}} - {{.Autore}}
-----------------------------
{{end}}
{{template "header" .}}
Contenuto della pagina:
{{range .Paragrafi}}
* {{.}}
{{end}}
{{template "footer" .}}
`))
dati := struct {
Titolo string
Anno int
Autore string
Paragrafi []string
}{
Titolo: "Guida Go",
Anno: 2026,
Autore: "Team Go",
Paragrafi: []string{"Introduzione", "Template", "Conclusione"},
}
tmpl.Execute(os.Stdout, dati)
}
Parsing di file template
Per caricare template da file esterni:
package main
import (
"html/template"
"net/http"
)
func main() {
// Carica un singolo file
tmpl := template.Must(template.ParseFiles("templates/pagina.html"))
// Carica piu file
tmpl = template.Must(template.ParseFiles(
"templates/layout.html",
"templates/header.html",
"templates/footer.html",
))
// Carica con pattern glob
tmpl = template.Must(template.ParseGlob("templates/*.html"))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
dati := map[string]string{
"Titolo": "Home Page",
"Contenuto": "Benvenuto nel sito!",
}
tmpl.ExecuteTemplate(w, "layout.html", dati)
})
http.ListenAndServe(":8080", nil)
}
html/template per la sicurezza
Il pacchetto html/template protegge automaticamente contro le iniezioni XSS:
package main
import (
"html/template"
"os"
)
func main() {
tmpl := template.Must(template.New("sicuro").Parse(`
<h1>{{.Titolo}}</h1>
<p>{{.Contenuto}}</p>
`))
dati := struct {
Titolo string
Contenuto string
}{
Titolo: "<script>alert('XSS')</script>",
Contenuto: "Testo con <b>HTML</b> & caratteri speciali",
}
tmpl.Execute(os.Stdout, dati)
// L'output avra i caratteri HTML escapati automaticamente
}
Se dovete inserire HTML fidato, usate il tipo template.HTML:
dati := struct {
Sicuro template.HTML
Insicuro string
}{
Sicuro: template.HTML("<strong>HTML fidato</strong>"),
Insicuro: "<script>alert('XSS')</script>",
}
Conclusione
Il sistema di template di Go e potente e sicuro. text/template e adatto per generare testo generico, email e file di configurazione, mentre html/template e essenziale per generare HTML sicuro. Le funzioni personalizzate, i template annidati e il parsing da file rendono il sistema flessibile e adatto a qualsiasi esigenza. Ricordate di usare sempre html/template quando generate HTML per proteggervi dalle iniezioni XSS.