如何渲染一个“模板的模板”,而不需要对每个操作进行转义?

huangapple go评论86阅读模式
英文:

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&#39;t want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status &quot;firing&quot; }}:{{ .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&#39;t want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status &quot;firing&quot; }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}

Render foo again.

While I can escape each portion of my desired literal with {{ &quot;{{&quot; }}, it feels a bit tedious.

I imagine that I should be able to do something like I want to render {{template &quot;outer&quot; .Foo}}. and call something like tmpl.ExecuteTemplate(&amp;buff, &quot;outer&quot;, 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 &lt;&lt;.Foo&gt;&gt;.

答案1

得分: 5

你可以更改模板的第一层分隔符:

tmpl := template.New("name").Delims("<<", ">>").Parse(...)

然后,将模板写成:

我想渲染 <<.Foo>>

但是我不想在这一行渲染任何内容比如 {{.Bar}}...
英文:

You can change the delimiters for the first level of template:

tmpl := template.New(&quot;name&quot;).Delims(&quot;&lt;&lt;&quot;,&quot;&gt;&gt;&quot;).Parse(...)

Then, write the template as:

I want to render &lt;&lt;.Foo&gt;&gt;.

but I don&#39;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 &quot;outer&quot;}}
I want to render {{.}}
{{end}}

{{$ignored := `but I don&#39;t want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status &quot;firing&quot; }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}`}}

{{template &quot;outer&quot; .Foo}}

{{$ignored}}

Render {{template &quot;outer&quot; .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(&quot;&quot;).Delims(&quot;&lt;&lt;&quot;, &quot;&gt;&gt;&quot;).Parse(`
I want to render &lt;&lt;.Foo&gt;&gt;.

but I don&#39;t want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status &quot;firing&quot; }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}

Render &lt;&lt;.Foo&gt;&gt; again.`))

This program:

var buf bytes.Buffer
if err := t.Execute(&amp;buf, map[string]any{&quot;Foo&quot;: &quot;foo&quot;}); err != nil {
    log.Fatal(err)
}
fmt.Println(buf.String())

prints:

I want to render foo.

but I don&#39;t want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status &quot;firing&quot; }}:{{ .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 &quot; in the line to be quoted, but that's not as bad as quoting all of the {{.

I want to render {{.Foo}}.

{{&quot;but I don&#39;t want to render anything on this line, like {{.Bar}} or this template: [{{ .Status | toUpper }}{{ if eq .Status \&quot;firing\&quot; }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}&quot;}}

Render {{.Foo}} again.

https://go.dev/play/p/ueqstNKVUWQ

huangapple
  • 本文由 发表于 2023年5月9日 01:11:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76202805.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定