Go语言模板引擎的使用可以分为三部分:定义模板文件、解析模板文件和模板渲染。

定义模板

按照相应的语法编写模板文件。

1
2
3
4
5
6
7
8
<html>
<head>
<title>模板文件</title>
</head>
<body>
hello {{ . }}
</body>
</html>

Go语言内置了文本模板引擎text/template和用于HTML文档的html/template。它们的作用机制可以简单归纳如下:

  • 模板文件通常定义为.tmpl.tpl为后缀(也可以使用其他的后缀),必须使用UTF8编码。
  • 模板文件中使用{{}}包裹和标识需要传入的数据。
  • 传给模板的数据可以通过点号.来访问,如果数据是复杂类型的数据,可以通过{{ .FieldName }}来访问它的字段。
  • {{}}包裹的内容外,其他内容均不做修改原样输出。

解析模板

系统定义了一些模板解析方法,获得模板对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 创建模板对象,并为其添加一个模板名称
func New(name string) *Template {}

// 解析字符串,比如template.New("name").Parse(src string) 创建模板对象,并完成模板解析。
func (t *Template) Parse(src string) (*Template, error) {}

// 解析模板文件得到模板对象,可以同时解析多个文件
func ParseFiles(filenames ...string) (*Template, error) {}

// 批量解析文件,比如解析当前目录下有以h开头的模板文件:template.ParseGlob("h*")
func ParseGlob(pattern string) (*Template, error) {}

解析模板的时候,有几个实用的方法

1
2
3
4
5
6
7
8
// 模板包里面有一个函数Must,它的作用是检测模板是否正确。
// 例如大括号是否匹配,注释是否正确的关闭,变量是否正确的书写
func Must(t *Template, err error) *Template

// Funcs方法向模板t的函数字典里加入参数funcMap内的键值对。
// 如果funcMap某个键值对的值不是函数类型或者返回值不符合要求会panic。
// 但是,可以对t函数列表的成员进行重写。方法返回t以便进行链式调用
func (t *Template) Funcs(funcMapFuncMap) *Template

模板渲染

模板渲染就是将后台的数据替换模板文件中的特定占位符,这里的特定字符是模板文件中的{{ . }}。系统定义了两个渲染方法:

1
2
func (t *Template) Execute(wr io.Writer, data interface{}) error {}
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {}

Execute用来渲染单个模板,如果是用 ParseFiles,ParseGlob一次性加载了多个模板,就需要用 ExecuteTemplate 选择模板来解析。

模板语法汇总

模板函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func xss2(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("demo/tpl/xss2.html")
	if err != nil {
		fmt.Println("模板解析异常 err = ", err)
		return
	}
	str := "<a href = 'http://www.baidu.com'>百度</a>"
	// 此时,我们想在页面上留下百度的跳转链接,但是这样写的话,肯定会被转义
	_ = t.Execute(w, str)
}

func xss3(w http.ResponseWriter, r *http.Request) {
	// 自定义模板函数,将特定字符串渲染成HTML标签输出显示,不要转义。
    // 注意:New传入的模板名不能带路径,下面ParseFiles解析模板则需要带路径
	t, err := template.New("xss3.html").Funcs(
		template.FuncMap {
			"safe": func(s string) template.HTML {
				return template.HTML(s)
			},
		},
	).ParseFiles("demo/tpl/xss3.html")

	if err != nil {
		fmt.Println("模板解析异常 err = ", err)
		return
	}
	str := "<a href = 'http://www.baidu.com'>百度</a>"
	_ = t.Execute(w, str)
}

模板嵌套

1
2
3
4
5
6
7
8
9
// 定义名称为 name 的 template
{{ define "name" }} T {{ end }}

// 执行名为 name 的 template
{{ template "name" }}
{{ template "name"  pipeline }}

// 先定义,并执行
{{ block "name" pipeline }} T {{ end }}

block等价于define定义一个名为name的模板,并执行这个模板,执行时将.设置为pipeline的值。 等价于:先 {{ define "name" }} T {{ end }} 再执行 {{ template "name" pipeline }}

参考:

(未完待续…)