Dynamic template creation in Go
How to use addParseTree in native Go templates
If you plan on spending time developing in Go, it’s only a matter of time before you hit an open source
project (Helm, Hugo, etc.) that uses Go’s native templating package. If you want to be able to create templates out
of templates dynamically, you’ll most likely want to look at using addParseTree
.
Let’s say you’re working with a couple of templates and you want to create a parent template that uses both of them.
func main() {
template1, err := template.New("template1").Parse("Template 1: {{ .Name }}")
must(err)
template2, err := template.New("template2").Parse("Template 2: {{ .Age }}")
must(err)
template3, err := template.New("template3").Parse(`{{ template "template1" .}}{{ template "template2" .}}`)
must(err)
}
In the creation of template3
, we want a way of letting it know what template1
and template2
should refer to or else you’ll get the following error when you try to run the .Execute
method on it :
panic: template: template3:1:11: executing "template3" at <{{template "template1" ....>: template "template1" not defined
This is where addParseTree
comes in. In the creation of a template, there’s an
embedded struct (*parse.Tree
) that you can refer to which is a tree representation of the parsed template. In a parent template (in our case, template3
) you can use the addParseTree
method to add a child template as a defined template.
func main() {
template1, err := template.New("template1").Parse("Template 1: {{ .Name }}")
must(err)
template2, err := template.New("template2").Parse("Template 2: {{ .Age }}")
must(err)
template3, err := template.New("template3").Parse(`{{ template "template1" .}}{{ template "template2" .}}`)
must(err)
_, err = template3.addParseTree(template1.Name(), template1.Tree)
must(err)
_, err = template3.addParseTree(template2.Name(), template2.Tree)
must(err)
// template3.Execute(...)
}
You should now be able to successfully .Execute
the parent template. You can even write a helper function if you need to do this repeatedly:
func addChildTemplate(parent *template.Template, child *template.Template) (*template.Template, error) {
return parent.addParseTree(child.Name(), child.Tree)
}