英文:
How to render a "template of templates", without escaping each action
问题
有人知道如何使用text/template
渲染一个“模板的模板”,只渲染特定的操作(即用{{...}}
包裹的内容),而其余部分将被视为字面值吗?
例如,给定以下模板:
I want to render {{.Foo}}.
but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
Render {{.Foo}} again.
我想要渲染以下输出:
I want to render foo.
but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
Render foo again.
虽然我可以使用{{ "{{" }}
来转义我想要保留的字面值部分,但这感觉有点繁琐。
我想象中应该可以这样做:I want to render {{template "outer" .Foo}}.
,然后调用tmpl.ExecuteTemplate(&buff, "outer", data)
来只渲染指定的“outer”操作。
我还想知道渲染一个“模板的模板”是否是一种代码异味,如果可能的话,是否应该用字符串替换我的“outer”模板,例如 I want to render <<.Foo>>
。
英文:
Does anyone know how to render a "template of templates" with text/template
, where only specific actions (ie: things wrapped in {{...}}
) will be rendered, and the rest will be treated as literals?
For example, given the following template:
I want to render {{.Foo}}.
but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
Render {{.Foo}} again.
I want to render the following output:
I want to render foo.
but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
Render foo again.
While I can escape each portion of my desired literal with {{ "{{" }}
, it feels a bit tedious.
I imagine that I should be able to do something like I want to render {{template "outer" .Foo}}.
and call something like tmpl.ExecuteTemplate(&buff, "outer", data)
to only render my specified "outer" actions.
I also wonder if rendering a "template of templates" is a code smell, and I should replace my "outer" template with a string/replace if possible, like I want to render <<.Foo>>
.
答案1
得分: 5
你可以更改模板的第一层分隔符:
tmpl := template.New("name").Delims("<<", ">>").Parse(...)
然后,将模板写成:
我想渲染 <<.Foo>>。
但是我不想在这一行渲染任何内容,比如 {{.Bar}}...
英文:
You can change the delimiters for the first level of template:
tmpl := template.New("name").Delims("<<",">>").Parse(...)
Then, write the template as:
I want to render <<.Foo>>.
but I don't want to render anything on this line, like {{.Bar}}...
答案2
得分: 3
{{define "outer"}}
我想要渲染{{.}}
{{end}}
{{$ignored := 但是我不想在这一行渲染任何东西,比如{{.Bar}}或者这个模板:[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
}}
{{template "outer" .Foo}}
{{$ignored}}
再次渲染{{template "outer" .Foo}}。
英文:
{{define "outer"}}
I want to render {{.}}
{{end}}
{{$ignored := `but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}`}}
{{template "outer" .Foo}}
{{$ignored}}
Render {{template "outer" .Foo}} again.
答案3
得分: 1
选项1:为内部和外部模板使用不同的分隔符。
t := template.Must(template.New("").Delims("<<", ">>").Parse(`
I want to render <<.Foo>>.
but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
Render <<.Foo>> again.`))
这个程序:
var buf bytes.Buffer
if err := t.Execute(&buf, map[string]interface{}{"Foo": "foo"}); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
输出:
I want to render foo.
but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
Render foo again.
https://go.dev/play/p/ueqstNKVUWQ
选项2:将整行作为字符串文字输出。这需要对行中的"
进行转义,但不需要对所有的{{
进行转义。
I want to render {{.Foo}}.
{{"but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status \"firing\" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}"}}
Render {{.Foo}} again.
https://go.dev/play/p/ueqstNKVUWQ
英文:
Option 1: Use different delimiters for the inner and outer templates.
t := template.Must(template.New("").Delims("<<", ">>").Parse(`
I want to render <<.Foo>>.
but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
Render <<.Foo>> again.`))
This program:
var buf bytes.Buffer
if err := t.Execute(&buf, map[string]any{"Foo": "foo"}); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
prints:
I want to render foo.
but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
Render foo again.
https://go.dev/play/p/ueqstNKVUWQ
Option 2: Emit the entire line as a string literal. This requires the "
in the line to be quoted, but that's not as bad as quoting all of the {{
.
I want to render {{.Foo}}.
{{"but I don't want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status \"firing\" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}"}}
Render {{.Foo}} again.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论