如何使用struct或variable值字段作为模板名称?

时间:2015-03-03 11:21:10

标签: templates go go-templates

我们可以通过{{define "home"}}定义模板名称,然后通过{{template "home"}}将其加载到其他(父)模板中。

如何通过变量值{{template .TemplateName}}加载模板。或者它不可能?

1 个答案:

答案 0 :(得分:12)

很遗憾,你不能。

{{template}}操作的语法:

{{template "name"}}
    The template with the specified name is executed with nil data.

{{template "name" pipeline}}
    The template with the specified name is executed with dot set
    to the value of the pipeline.

要包含的模板的名称是常量字符串,它不是管道,它可能在执行期间根据参数而变化。

如果允许的语法是:

{{template pipeline}}

那么你可以使用{{template .TemplName}}这样的东西,但由于语法只允许使用常量字符串,所以你不能。

Rob的推理为什么不允许动态模板调用(source):

  

我们希望模板语言可以静态分析,因此模板调用的上下文是清晰,可检查和可锁定的。如果调用点完全是动态的,则无法完成。类似地,如果模板可以属于多个集合,则其上下文可以以需要同时分析所有集合的方式在集合之间不同。由于这两个约束很容易解决,如果你想以更高级别的包丢失那些静态检查为代价,控制基本模板实现中的情况似乎是明智的。如果约束条件清晰,则更高级别的包(例如假设的仅HTML包装器)可以保证不会更容易解决。

备选方案#1:首先执行Includable Template

您可以做的是先执行您想要包含的模板,然后将结果插入您想要包含的模板。您可以使用特殊类型在插入时不要转义内部模板的结果,例如在HTML模板的情况下使用html.HTML

见这个例子:

func main() {
    t := template.Must(template.New("t").Parse(t))
    template.Must(t.New("t1").Parse(t1))

    params := struct {
        Name  string
        Value interface{}
    }{"t1", nil}
    b := bytes.Buffer{}
    t.ExecuteTemplate(&b, params.Name, nil)
    params.Value = template.HTML(b.String())

    t.Execute(os.Stdout, params)
}

const t = `<html><body>
Now I will include template with name: {{.Name}}
{{.Value}}
</body>/html>`

const t1 = `I'm template <b>t1</b>.`

输出:

<html><body>
Now I will include template with name: t1
I'm template <b>t1</b>.
</body>/html>

Go Playground上尝试。

模板t1的结果未插入。如果你遗漏template.HTML

params.Value = b.String()

t1将被插入转义,如下所示:

<html><body>
Now I will include template with name: t1
I&#39;m template &lt;b&gt;t1&lt;/b&gt;.
</body>/html>

备选方案#2:重组模板

您可以重新构建模板,而不是在您希望包含具有不同名称的模板的情况下。

示例:您可能希望创建一个页面,其中包含page模板,如下所示:

<html><body>
    Title, headers etc.
    {{template .Page}}
    Footers
</body></html>

您可以将其重组为:

header模板:

<html><body>
    Title, headers, etc.

footer模板:

    Footers
</body></html

您的网页模板包含headerfooter,如下所示:

{{template "header" .}}
    Page content comes here.
{{template "footer" .}}

备选方案#3:使用{{if}}操作和预定义名称

如果您之前知道模板名称并且它不是令人筋疲力尽的列表,则可以使用{{if}}模板操作来包含所需的模板。例如:

{{if eq .Name "page1"}}

    {{template "page1" .}}

{{else if eq .Name "page2"}}

    {{template "page2" .}}
    ...

{{end}}

备选方案#4:修改静态模板文本

这里的想法是您可以手动修改外部模板的静态文本,并插入要包含的内部模板的名称。

此方法的缺点是,在插入内部模板的名称后,您必须重新解析模板,因此我不建议这样做。