Go provides two similar template packages, one for general text and another for HTML. The HTML package works essentially the same way at the text templates, but protects against some web-specific security concerns.
The overview of the text/template
packages is a good starting point.
Execute a template by applying it to a data structure.
package main
import (
"os"
"text/template"
)
type Inventory struct {
Material string
Count uint
}
func main() {
planet := "Mars"
tmpl, _ := template.New("launch").Parse("Launch the mission to {{.}}!\n")
tmpl.Execute(os.Stdout, planet)
sweaters := Inventory{"wool", 17}
tmpl, _ = template.New("itemcount").Parse("{{.Count}} items are made of {{.Material}}.\n")
tmpl.Execute(os.Stdout, sweaters)
}
Execution of the template walks the data structure.
Annotations ({{foo}}
) in the template refer to elements of the data structure.
Execution of the template sets a cursor to the value at its current location as it walks the data structure.
A dot ({{.}}
) represents the cursor.
The second parameter of Execute
sets the cursor’s initial value.
We can manually change the current context using the with
action:
{{with pipeline}} T {{end}}
A template is UTF-8 text.
All text is output verbatim, except for “actions” enclosed between {{
and }}
.
Well, not necessarily verbatim — {{.x -}} × {{- .y}}
trims the leading and trailing whitespace around ×
in the output.
Actions include loops, conditionals, and variable assignment:
{{/* A comment. */}}
{{define "embeddedtemplate"}} Thing: {{.}} {{end}}
{{template "embeddedtemplate" .Foo}}
{{with .MyValue}} A thing. {{else}} Nothing {{end}}
<h1>{{.Title}}<h1>
<ul>
{{range .Todos}}
{{if .Done}}
<li class="done">{{.Title}}</li>
{{else}}
<li>{{.Title}}</li>
{{end}}
{{end}}
</ul>
<ol>
{{range .Steps}}
{{$s := .Name}}
<ol>
{{range .SubSteps}}
<li><b>{{$s}}:</b> {{.}}</li>
{{end}}
</ol>
{{end}}
</ol>
The template
action executes the named template, embedded within the current template (i.e., an “include”).
Name templates using the define
action.
The template
action may be executed with nil data or we can pass in data from a pipeline:
{{template "name"}}
{{template "name" pipeline}}
Go templates have a “pipeline” concept, similar to a unix shell pipeline.
In a Go template, a pipeline might be a single simple value or a function call with multiple arguments.
Combine a sequence of chained commands with |
;
the output from one commands becomes the input to the next.
Parse a template from a file:
tmpl := template.Must(template.ParseFiles("foo.html")
(Note: “Since the templates created by ParseFiles are named by the base names of the argument files, t should usually have the name of one of the (base) names of the files. If it does not, depending on t’s contents before calling ParseFiles, t.Execute may fail. In that case use t.ExecuteTemplate to execute a valid template.”)
Use a template in an http request handler:
func(w http.ResponseWriter, r *http.Request) {
tmpl.Execute(w, data)
}
Go templates can capture the results of a pipeline in a variable.
Template variables start with $
.
$variable := pipeline
range $index, $element := pipeline
For efficiency, parse templates once only, then execute them as needed.
Since ParseFiles
is variadic, have it parse all the files in one go and save them to a slice.
var templates = template.Must(template.ParseGlob(filepath.Join("templates", "*.html")))
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
err := templates.ExecuteTemplate(w, tmpl, p)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}