是否可以使用标准库在 Go 中嵌套模板?

Posted

技术标签:

【中文标题】是否可以使用标准库在 Go 中嵌套模板?【英文标题】:Is it possible to have nested templates in Go using the standard library? 【发布时间】:2012-07-13 03:23:56 【问题描述】:

如何在 python 运行时中获得像 Jinja 这样的嵌套模板。 TBC 我的意思是我如何让一堆模板继承自基本模板,只需归档基本模板的块,就像 Jinja/django-templates 一样。是否可以在标准库中只使用html/template

如果这不可能,我的替代方案是什么。胡子似乎是一种选择,但我会错过html/template 的那些微妙的功能吗?比如上下文敏感的转义等?还有哪些其他选择?

(环境:Google App Engin,Go runtime v1,Dev - Mac OSx lion)

感谢阅读。

【问题讨论】:

【参考方案1】:

是的,这是可能的。 html.Template 实际上是一组模板文件。如果您执行此集中定义的块,则它可以访问此集中定义的所有其他块。

如果您自己创建此类模板集的地图,您将拥有与 Jinja / Django 提供的基本相同的灵活性。唯一的区别是html/template包不能直接访问文件系统,所以你必须自己解析和组合模板。

考虑以下示例,其中包含两个都继承自“base.html”的不同页面(“index.html”和“other.html”):

// Content of base.html:
define "base"<html>
  <head>template "head" .</head>
  <body>template "body" .</body>
</html>end

// Content of index.html:
define "head"<title>index</title>end
define "body"indexend

// Content of other.html:
define "head"<title>other</title>end
define "body"otherend

以及下面的模板集图:

tmpl := make(map[string]*template.Template)
tmpl["index.html"] = template.Must(template.ParseFiles("index.html", "base.html"))
tmpl["other.html"] = template.Must(template.ParseFiles("other.html", "base.html"))

您现在可以通过调用来呈现您的“index.html”页面

tmpl["index.html"].Execute("base", data)

你可以通过调用来呈现你的“other.html”页面

tmpl["other.html"].Execute("base", data)

通过一些技巧(例如,模板文件的命名约定一致),甚至可以自动生成 tmpl 映射。

【讨论】:

是否可以有默认数据,例如“head”? 我将在这里添加,为了渲染实际的模板,我必须调用tmpl["index.html"].ExecuteTemplate(w, "base", data) base.html 被解析和存储两次。您还可以使用 golang.org/pkg/text/template/#example_Template_share 中的 Clone() 函数 我在将数据传递到嵌套模板时遇到问题。来自 .SomeData 的数据不会显示在内部模板中。外部作品。 template.ParseFiles("index.html", "base.html")template.ParseFiles("base.html", "index.html") 是否重要?【参考方案2】:

注意,当你执行你的基础模板时,你必须将值传递给子模板,这里我只是传递“.”,这样所有的东西都会传递下去。

模板一显示 .

define "base"
<html>
        <div class="container">
            .
            template "content" .
        </div>
    </body>
</html>
end

模板二显示传递给父级的 .domains。

define "content"
.domains
end

注意,如果我们使用 template "content" . 而不是 template "content" .,则无法从内容模板访问 .domains。

DomainsData := make(map[string]interface)
    DomainsData["domains"] = domains.Domains
    if err := groupsTemplate.ExecuteTemplate(w, "base", DomainsData); err != nil 
        http.Error(w, err.Error(), http.StatusInternalServerError)
    

【讨论】:

传递模型是我坚持的一个细节。 ;) 谢谢 我也是 - 花了一点时间才弄清楚 :) 什么!我不敢相信 template 占位符末尾的小点有这么多含义!为什么教程甚至官方 Go 文档中都没有提到这一点?我很震惊......但也很高兴找到你的答案!非常感谢,现在我的多层嵌套模板工作得很好! 完全一样,我也想弄清楚!【参考方案3】:

使用过其他模板包,现在我主要使用标准 html/模板包,我想我很天真,没有欣赏它提供的简单性和其他好东西。我使用非常相似的方法来接受以下更改

你不需要用额外的base 模板来包装你的布局,为每个解析的文件创建一个模板块,所以在这种情况下它是多余的,我也喜欢使用新版本的 go 中提供的块操作,它允许您拥有默认的块内容,以防您没有在子模板中提供一个

// base.html
<head>block "head" . Default Title end</head>
<body>block "body" . default body end</body>

而且你的页面模板可以和

// Content of index.html:
define "head"<title>index</title>end
define "body"indexend

// Content of other.html:
define "head"<title>other</title>end
define "body"otherend

现在执行你需要这样调用的模板

tmpl["index.html"].ExecuteTemplate(os.Stdout, "base.html", data)

【讨论】:

【参考方案4】:

使用 Pongo,它是 Go 模板的超集,支持 extends 和 block 标签进行模板继承,就像 Django。

【讨论】:

【参考方案5】:

几天来我一直在回到这个答案,终于硬着头皮为此写了一个小的抽象层/预处理器。它基本上是:

将“扩展”关键字添加到模板。 允许覆盖“定义”调用(因此可以使用 greggory 的默认值) 允许未定义的“模板”调用,它们只给出一个空字符串 设置默认值。在“模板”中调用 .父母的

https://github.com/daemonl/go_sweetpl

【讨论】:

以上是关于是否可以使用标准库在 Go 中嵌套模板?的主要内容,如果未能解决你的问题,请参考以下文章

go语言标准库之http/template

如何使用标准库在 python 中解析格式错误的 HTML

Go语言标准库之http/template

Go语言标准库之http/template

Go日志库——log和logrus

go标准库的text/template