英文:
Usage of variables in a nested template which is also defined as a variable in a go template?
问题
package main
import (
"os"
"text/template"
)
type Todo struct {
Name string
Description string
Subtemplate string
}
func main() {
td := Todo{
Name: "Test name",
Description: "Test description",
Subtemplate: "Subtemplate {{.Name}}",
}
t, err := template.New("todos").Parse(`{{template "subtemplate" .}} You have a task named "{{ .Name}}" with description: "{{ .Description}}"`)
if err != nil {
panic(err)
}
// Define the subtemplate
_, err = t.New("subtemplate").Parse(td.Subtemplate)
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, td)
if err != nil {
panic(err)
}
}
上述代码的结果是:
Subtemplate Test name You have a task named "Test name" with description: "Test description"
这意味着子模板中的变量.Name
没有被解析(可能是因为设计上不可能,需要一种递归调用的方式)。有没有其他方法可以实现这个效果?
对于使用template.FuncMap
定义的模板函数也应该适用。谢谢。
英文:
The idea is to define a variable for a go template which is also a template using variables (a nested template) like this:
package main
import (
"os"
"text/template"
)
type Todo struct {
Name string
Description string
Subtemplate string
}
func main() {
td := Todo{
Name: "Test name",
Description: "Test description",
Subtemplate: "Subtemplate {{.Name}}",
}
t, err := template.New("todos").Parse("{{.Subtemplate}} You have a task named \"{{ .Name}}\" with description: \"{{ .Description}}\"")
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, td)
if err != nil {
panic(err)
}
}
The result of the code above is however:
Subtemplate {{.Name}} You have a task named "Test name" with description: "Test description"
means the variable .Name
in the subtemplate is not resolved (probably by design not possible, would require some kind of a recursive call). Is there any/other way to achieve this effect?
It should work for the template functions defined using template.FuncMap
too. Thanx.
答案1
得分: 2
你可以注册一个函数来解析字符串模板并执行它。
该函数可以像这样:
func exec(body string, data interface{}) (string, error) {
t, err := template.New("").Parse(body)
if err != nil {
return "", err
}
buf := &strings.Builder{}
err = t.Execute(buf, data)
return buf.String(), err
}
你将模板主体文本和用于模板执行的数据传递给它。它会执行并返回结果。
一旦注册,你可以在模板中这样调用它:
{{exec .Subtemplate .}}
完整示例:
td := Todo{
Name: "Test name",
Description: "Test description",
Subtemplate: "Subtemplate {{.Name}}",
}
t, err := template.New("todos").Funcs(template.FuncMap{
"exec": func(body string, data interface{}) (string, error) {
t, err := template.New("").Parse(body)
if err != nil {
return "", err
}
buf := &strings.Builder{}
err = t.Execute(buf, data)
return buf.String(), err
},
}).Parse("{{exec .Subtemplate .}} You have a task named \"{{ .Name}}\" with description: \"{{ .Description}}\"")
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, td)
if err != nil {
panic(err)
}
这将输出(在Go Playground上尝试):
Subtemplate Test name You have a task named "Test name" with description: "Test description"
请注意,如果子模板在运行时不会更改,你应该预先解析它并将生成的模板(*template.Template
)存储起来,以避免每次执行模板时都进行解析。
英文:
You can register a function which parses a string template and executes it.
The function could look like this:
func exec(body string, data any) (string, error) {
t, err := template.New("").Parse(body)
if err != nil {
return "", err
}
buf := &strings.Builder{}
err = t.Execute(buf, data)
return buf.String(), err
}
You pass the template body text and the data for template execution to it. It executes it and returns the result.
Once registered, you can call it like this from a template:
{{exec .Subtemplate .}}
Full example:
td := Todo{
Name: "Test name",
Description: "Test description",
Subtemplate: "Subtemplate {{.Name}}",
}
t, err := template.New("todos").Funcs(template.FuncMap{
"exec": func(body string, data any) (string, error) {
t, err := template.New("").Parse(body)
if err != nil {
return "", err
}
buf := &strings.Builder{}
err = t.Execute(buf, data)
return buf.String(), err
},
}).Parse("{{exec .Subtemplate .}} You have a task named \"{{ .Name}}\" with description: \"{{ .Description}}\"")
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, td)
if err != nil {
panic(err)
}
This will output (try it on the Go Playground):
Subtemplate Test name You have a task named "Test name" with description: "Test description"
Note that if the subtemplate does not change during runtime, you should pre-parse it and store the resulting template (*template.Template
) to avoid having to parse it each time you execute the template.
答案2
得分: 1
如果你不介意性能问题,你可以渲染两次...
package main
import (
"os"
"text/template"
"bytes"
)
type Todo struct {
Name string
Description string
Subtemplate string
}
func main() {
td := Todo{
Name: "测试名称",
Description: "测试描述",
Subtemplate: "子模板 {{.Name}}",
}
t, err := template.New("todos").Parse("{{.Subtemplate}} 你有一个名为“{{.Name}}”的任务,描述为:“{{.Description}}”")
if err != nil {
panic(err)
}
buffer := &bytes.Buffer{}
err = t.Execute(buffer, td)
tc, err := template.New("todo2").Parse(string(buffer.Bytes()))
if err != nil {
panic(err)
}
err = tc.Execute(os.Stdout, td)
if err != nil {
panic(err)
}
}
英文:
You can render twice if you don't mind for peformance ...
package main
import (
"os"
"text/template"
"bytes"
)
type Todo struct {
Name string
Description string
Subtemplate string
}
func main() {
td := Todo{
Name: "Test name",
Description: "Test description",
Subtemplate: "Subtemplate {{.Name}}",
}
t, err := template.New("todos").Parse("{{.Subtemplate}} You have a task named \"{{ .Name}}\" with description: \"{{ .Description}}\"")
if err != nil {
panic(err)
}
buffer := &bytes.Buffer{}
err = t.Execute(buffer, td)
tc, err := template.New ("todo2").Parse(string (buffer.Bytes ()))
if err != nil {
panic (err)
}
err = tc.Execute(os.Stdout, td)
if err != nil {
panic(err)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论