Text and HTML templates
suggest changeImagine you’re working on a web application and need to return HTML that lists most recent tweets. You need to load list of tweets from a database and create HTML based on that information.
Building that HTML string by building smaller strings and concatenating them with +
would be tedious.
Packages text/template
and html/template
in Go standard library make implement data-driven templates for generating textual output:
var tmplStr = `User {{.User}} has {{.TotalTweets}} tweets.
{{- $tweetCount := len .RecentTweets }}
Recent tweets:
{{range $idx, $tweet := .RecentTweets}}Tweet {{$idx}} of {{$tweetCount}}: '{{.}}'
{{end -}}
Most recent tweet: '{{index .RecentTweets 0}}'
`
t := template.New("tweets")
t, err := t.Parse(tmplStr)
if err != nil {
log.Fatalf("template.Parse() failed with '%s'\n", err)
}
data := struct {
User string
TotalTweets int
RecentTweets []string
}{
User: "kjk",
TotalTweets: 124,
RecentTweets: []string{"hello", "there"},
}
err = t.Execute(os.Stdout, data)
if err != nil {
log.Fatalf("t.Execute() failed with '%s'\n", err)
}
User kjk has 124 tweets.
Recent tweets:
Tweet 0 of 2: 'hello'
Tweet 1 of 2: 'there'
Most recent tweet: 'hello'
Each template has a name. template.New("tweets")
creates an empty template with name tweets
.
t.Parse(s string)
parses the template.
t.Execute(w io.Writer, v interface{})
executes the template with a given value and writing the result to an io.Writer
.
{{ ... }}
is an action are instructions for templating engine.
{{.TweetCount}}
means printing the value of TweetCount
in current context.
Data passed to a template can be hierarchical (i.e. a struct withing a struct within a struct…).
Current context .
refers to current scope within the data.
Initial .
refers to top-level scope:
tmplStr := "Data: {{.}}\n"
t := template.Must(template.New("simple").Parse(tmplStr))
execWithData := func(data interface{}) {
err := t.Execute(os.Stdout, data)
if err != nil {
log.Fatalf("t.Execute() failed with '%s'\n", err)
}
}
execWithData(5)
execWithData("foo")
st := struct {
Number int
Str string
}{
Number: 3,
Str: "hello",
}
execWithData(st)
Data: 5
Data: foo
Data: {3 hello}
Values that don’t have pre-defined formatting are printed using Stringer
interface. For custom formatting of your type in a template implement String() string
method.
{{range .Tweets}}{{end}}
evaluates inner part for every element of []string
slice Tweets
and sets current context .
within the inner part to elements of Tweets
slice.
{{index .RecentTweets 0}}
is equivalent to RecentTweets[0]
in Go code.
Text in a template is copied verbatim. Having to preserve whitespace can lead to ugly templates.
To help write more readable templates We can add -
at the beginning or end of action as seen in {{end -}}
.
This remove whitespace before or after the action.
{{range .RecentTweets}}
changes variable scope and we don’t have access to data outside. If we need to access data from upper scope, we can define variables like {{ $tweetCount := len .RecentTweets }}
.