Template in Go
text/template
和 html/template
包可以将变量的值代入文本或 HTML 模板,用于输出更精细的格式,将输出格式和代码彻底分离。
模板可以是字符串或文件,它包含若干个用 {{}}
包起来的部分(称为 action)。大部分字符串会按照字面值打印,action 则会触发一些行为。
模板语言作为一套记号,可以用来打印值,选择结构体字段,调用函数、方法,表达控制流(if-else
, range
),初始化其它模板。
每个 action 包含一个模板语言的语句。
一个 action 中,.
表示当前值,.
的初始值是当前模板的参数。
{{range .Items}}
和 {{end}}
构成一个循环。
|
表示将上一个操作的结果作为下一个操作的参数,类似 shell 管道。
使用模板的步骤:
- 解析模板
- 只需执行一次。
- 对输入的数据执行模板
const templ = `{{.TotalCount}} issues:
{{range .Items}}-------------------------
Number: {{.Number}}
User: {{.User.Login}}
Title: {{.Title | printf "%.64s"}}
Age: {{.CreatedAt | daysAgo}} days
{{end}}`
// printf 即 fmt.Sprintf;daysAgo 是自定义函数
func daysAgo(t time.Time) int {
return int(time.Since(t).Hours() / 24)
}
// chaining methods
report, err := template.New("report").
Funcs(template.FuncMap{"daysAgo": daysAgo}).
Parse(templ)
if err != nil {
log.Fatal(err)
}
// // template.Must helper makes error handling more convenient
// var report = template.Must(template.New("issuelist").
// Funcs(template.FuncMap{"daysAgo": daysAgo}).
// Parse(templ))
if err := report.Execute(os.Stdout, inputs); err != nil {
log.Fatal(err)
}
// 13 issues:
// ----------------------------------------
// Number: 5680
// User: eaigner
// Title: encoding/json: set key converter on en/decoder
// Age: 750 days
// ----------------------------------------
// Number: 6050
// User: gopherbot
// Title: encoding/json: provide tokenizer
// Age: 695 days
// ----------------------------------------
// ...
“index x 1 2 3” is, in Go syntax, x[1][2][3]
. Each indexed item must be a map, slice, or array.
kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}'
html/template
和 text/template
使用相同的接口,增加了对 HTML,JavaScript,CSS,URL 中的字符串的自动 escape,可以防止注入攻击。
<!-- html/template: 对 <,>,&, 等 HTML 保留字符 escape 后,浏览器引擎读到的是字面量,不具有特殊含义,页面上则正常显示对应字符。-->
x/net/html: void element <link> has child nodes
html/template: escape xmldesc as <?xml
<a href='https://github.com/golang/go/issues/10535'>x/net/html: void element <link> has child nodes</a>
<a href='https://github.com/golang/go/issues/3133'>html/template: escape xmldesc as &lt;?xml</a>
<!-- text/template:不对保留字符进行 escape,浏览器将 <> 作为标签来识别,页面上也就不能正常显示 -->
x/net/html: void element has child nodes
html/template: escape xmldesc as <?xml
<a href='https://github.com/golang/go/issues/10535'>x/net/html: void element <link> has child nodes</a>
<a href='https://github.com/golang/go/issues/3133'>html/template: escape xmldesc as <?xml</a>
对于可信的 HTML 而言,可以用 template.HTML
来阻止自动 escape 的行为。对于 JavaScript,CSS 和 URL也存在类似的方法。
const templ = `<p>A: {{.A}}</p><p>B: {{.B}}</p>`
t := template.Must(template.New("escape").Parse(templ))
var data struct {
A string // untrusted plain text
B template.HTML // trusted HTML
}
data.A = "<b>Hello!</b>" // 渲染成 <b>Hello!</b>
data.B = "<b>Hello!</bb>" // 渲染成加粗的 Hello!
if err := t.Execute(os.Stdout, data); err != nil {
log.Fatal(err)
}
References