Reputation: 6541
I have two golang html templates, as follows:
var m map[string]string
m = make(map[string]string)
m["First"] = `<html>
<body>First template type {{.First}}
</html>`
m["Second"] = `<html>
<body>Second template type {{.SecondF1}} {{.SecondF2}}
</html>`
The first html template takes only one argument, named First
whereas the second template needs two arguments, named SecondF1
and SecondF2
.
Now I have a struct which has two fields, one for receiving a template name and another for receiving the template arguments.
type tmplReceiver struct {
TmplName string
TmplArgs string // Receives JSON string
}
Now, examples of instances for the above structs could be:
var i, j tmplReceiver
i.TmplName = "First"
i.TmplArgs = `{"Field1": "First Template Argument"}`
j.TmplName = "Second"
j.TmplArgs = `{
"SecondF1": "Second template First Argument",
"SecondF2": "Second template Second Argument"
}`
Now I can get the Template string by using the map, for example:
tmplStr := m[i.TmplName] (or)
tmplStr := m[j.TmplName]
tmpl, _ = template.New("email").Parse(tmplStr)
However, how do I get the template to be executed for all the possible template types, with a single tmpl.Execute
statement. In other words, if I want to have the following code:
var buff bytes.Buffer
if err := tmpl.Execute(&buff, tmplPtr); err != nil {
log.Fatal(err)
}
log.Println(buff.String())
How do I get the tmplPtr
to be valid, irrespective of how many templates I have (First
, Second
, etc.) and each of these templates can have a variable number of arguments (First
has only one arg, whereas Second
has two args, etc.)
I do not want to write N different tmpl.Execute
statements with an if
block for each template name. Is there any other alternative approach to solve this ? Thanks.
Upvotes: 0
Views: 1126
Reputation: 13187
Neither json.Unmarshal
nor template.Execute
cares about the actual type of the data, this will all be handled at runtime. So you can just parse the json to an interface{}
and pass that to your templates. Provided that the json data contains the fields that are expected by the template to which you pass the data, this will just work fine.
package main
import (
"bytes"
"encoding/json"
"fmt"
"html/template"
)
var templates = map[string]*template.Template{
"A": template.Must(template.New("A").Parse("{{ .A }}")),
"B": template.Must(template.New("B").Parse("{{ .B }} and {{ .C.D }}")),
}
type tmplReceiver struct {
TmplName string
TmplArgs string
}
func main() {
receivers := []tmplReceiver{
tmplReceiver{"A", `{"A": "Value for A"}`},
tmplReceiver{"B", `{"B": "Value for B", "C": { "D": "Value for D" }}`},
}
for _, receiver := range receivers {
var data interface{}
json.Unmarshal([]byte(receiver.TmplArgs), &data)
var buffer bytes.Buffer
templates[receiver.TmplName].Execute(&buffer, data)
fmt.Println(buffer.String())
}
}
Which prints
Value for A
Value for B and Value for D
Upvotes: 0