英文:
golang templates processing and generics
问题
我有两个golang的html模板,如下所示:
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>`
第一个html模板只需要一个参数,名为First
,而第二个模板需要两个参数,分别为SecondF1
和SecondF2
。
现在我有一个结构体,它有两个字段,一个用于接收模板名称,另一个用于接收模板参数。
type tmplReceiver struct {
TmplName string
TmplArgs string // 接收JSON字符串
}
上述结构体的实例示例可以是:
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"
}`
现在,我可以使用映射来获取模板字符串,例如:
tmplStr := m[i.TmplName] // 或者
tmplStr := m[j.TmplName]
然后,可以使用以下代码执行模板,以获取所有可能的模板类型:
var buff bytes.Buffer
if err := tmpl.Execute(&buff, tmplPtr); err != nil {
log.Fatal(err)
}
log.Println(buff.String())
但是,无论我有多少个模板(First
、Second
等),以及每个模板可以有多少个参数(First
只有一个参数,而Second
有两个参数等),我如何使tmplPtr
有效?
我不想为每个模板名称编写N个不同的tmpl.Execute
语句,并带有一个if
块。是否有其他替代方法来解决这个问题?谢谢。
英文:
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.
答案1
得分: 0
json.Unmarshal
和template.Execute
都不关心数据的实际类型,这些都将在运行时处理。因此,你可以将JSON解析为interface{}
,然后将其传递给模板。只要JSON数据包含模板所需的字段,这将正常工作。
以下是翻译好的代码:
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": "A的值"}`},
tmplReceiver{"B", `{"B": "B的值", "C": { "D": "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())
}
}
输出结果为:
A的值
B的值 and D的值
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论