Go Templating
There are two packages that support templating in Go. One package is for text templating and the other is for HTML templating. Both packages are very similar and support the same syntax. The main difference between the two packages is that the html/template package will automatically escape HTML characters to prevent XSS attacks, while the text/template package does not provide this security feature.
Basic Template Usage
package main
import (
"os"
"text/template"
)
func main() {
tmpl := template.Must(template.New("example").Parse("Hello, !"))
tmpl.Execute(os.Stdout, struct{ Name string }{"World"})
// Output: Hello, World!
}
Variables
Go templates support variables. Variables are defined using the following syntax.
{{- $variableName := .variableValue -}}
Conditional Branching
Golang templates support conditional branching using the if, else and end keywords.
{{- if .variableValue -}}
{{- else -}}
{{- endif -}}
Function / Operator | Description | Example |
---|---|---|
eq | Equals, arg1 == arg2 | {{ if eq arg1 arg2 }} … {{ endif }} |
ne | Not Equals, arg1 != arg2 | {{ if ne arg1 arg2 }} … {{ endif }} |
lt | Less Than, arg1 < arg2 | {{ if lt arg1 arg2 }} … {{ endif }} |
le | Less Than or Equal To, arg1 <= arg2 | {{ if le arg1 arg2 }} … {{ endif }} |
gt | Greater Than, arg1 > arg2 | {{ if gt arg1 arg2 }} … {{ endif }} |
ge | Greater Than or Equal To, arg1 >= arg2 | {{ if ge arg1 arg2 }} … {{ endif }} |
Iteration
Golang templates support iteration using the range keyword. The range action allows you to iterate over arrays, slices, maps, channels, or strings.
{{- range .variableValue -}}
<!-- Inside the range, "." is set to the current item -->
{{ . }}
{{- end -}}
Accessing Index and Value
For slices and arrays, you can access both the index and value:
{{- range $index, $element := .Slice -}}
<!-- $index contains the current position -->
<!-- $element contains the value -->
{{ $index }}: {{ $element }}
{{- end -}}
Iterating Over Maps
For maps, you get key-value pairs:
{{- range $key, $value := .Map -}}
{{ $key }}: {{ $value }}
{{- end -}}
Example: Rendering a List
<ul>
{{- range .Items -}}
<li>{{ .Name }}: {{ .Price }}</li>
{{- end -}}
</ul>
Nested Ranges
You can nest range actions for multi-dimensional data:
{{- range .Sections -}}
<h2>{{ .Title }}</h2>
<ul>
{{- range .Items -}}
<li>{{ .Name }}</li>
{{- end -}}
</ul>
{{- end -}}
Empty Check with else
You can handle empty collections with an else clause:
{{- range .Items -}}
<!-- This executes for each item -->
{{ .Name }}
{{ else }}
<!-- This executes if .Items is empty or nil -->
No items found
{{- end -}}
Breaking Out of a Range
Go templates don’t support a break statement, but you can use with/if combinations for conditional processing:
{{- range .Items -}}
{{- if .ShouldProcess -}}
{{ .Name }}
{{- end -}}
{{- end -}}
Functions
Golang templates support functions. The following functions are available by default:
Function | Description | Example |
---|---|---|
and |
Returns the boolean AND of its arguments | ... |
or |
Returns the boolean OR of its arguments | ... |
not |
Returns the boolean NOT of its argument | ... |
len |
Returns the length of a string, slice, map or array | `` |
index |
Returns the result of indexing its first argument by the following arguments | `` |
print |
Formats using default formats | `` |
printf |
Formats according to a format specifier | `` |
println |
Like print but adds a newline | `` |
html |
Safely escapes for HTML | `` |
js |
Safely escapes for JavaScript | `` |
call |
Calls the first argument with the remaining arguments as parameters | `` |
Function Examples
Using len
with conditionals:
{{ if eq (len .Items) 0 }}
<p>No items found</p>
{{ else }}
<p>Found {{ len .Items }} items</p>
{{ end }}
Using index
to access array elements:
{{ index .Array 0 }} <!-- First element -->
{{ index .NestedMap "key" "subkey" }} <!-- Nested access -->
String formatting with printf
:
{{ printf "Name: %-10s Age: %3d" .Name .Age }}
Adding Custom Functions
You can extend templates with custom functions by using the FuncMap
:
package main
import (
"html/template"
"os"
"strings"
"time"
)
func main() {
// Create a custom function map
funcMap := template.FuncMap{
"upper": strings.ToUpper,
"formatDate": func(t time.Time) string {
return t.Format("2006-01-02")
},
"add": func(a, b int) int {
return a + b
},
}
// Create a template with the function map
tmpl := template.New("example").Funcs(funcMap)
// Parse template with function usage
tmpl, err := tmpl.Parse(`
Upper:
Date:
Sum:
`)
if err != nil {
panic(err)
}
// Execute template
data := struct {
Date time.Time
}{
Date: time.Now(),
}
tmpl.Execute(os.Stdout, data)
}
Output:
Upper: HELLO
Date: 2023-10-15
Sum: 15