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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package main
import (
"html/template"
"os"
"fmt"
)
type Person struct {
Id string
UserName string
Age int
Contact map[string]string
}
func (p Person) Say(msg string) string {
return msg
}
func test1() string {
return "test1"
}
func test2(msg string) string {
return msg + "test2"
}
func test3(a int) bool {
if a == 3 {
return true
}
return false
}
func sum() func(nums ...int) (int, error) {
return func(nums ...int) (int, error) {
sum := 0;
for _, v := range nums {
sum += v
}
return sum, nil
}
}
func main() {
//创建一个模板
t := template.New("test")
//注释
t, _ = t.Parse(`{{/*我是注释*/}}`)
t.Execute(os.Stdout, nil)

//输出单个字符串
t2 := template.New("test")
// {{.}}输出当前对象的值
t2, _ = t2.Parse(`{{.}}`)
p := "test"
//输出字符串
t2.Execute(os.Stdout, p)
fmt.Println();

//输出结构中字段的值
t3 := template.New("test");
// {{.字段名}}输出对象中字段的值
//注意字段是可导出的,首字母大写
t3, _ = t3.Parse(`{{.Id}} {{.UserName}} {{.Age}}`);
t3.Execute(os.Stdout, Person{"001", "test", 11, nil});
fmt.Println()

//调用结构的方法
t4 := template.New("test")
// {{.方法 参数1 参数2}}
//参数依次传入方法,输出返回值
t4, _ = t4.Parse(`{{.Say "hello"}}`)
t4.Execute(os.Stdout, Person{"002", "test2", 22, nil})
fmt.Println()

//模板中定义变量
t5 := template.New("test")
// {{$变量名}} 输出模板中定义的变量
t5, _ = t5.Parse(`{{$a := "模板中定义的变量"}} {{$a}}`)
t5.Execute(os.Stdout, nil)
fmt.Println()

//模板函数
t6 := template.New("test")
//注册模板函数
t6.Funcs(template.FuncMap{"test1": test1})
t6.Funcs(template.FuncMap{"test2": test2})
// {{函数名}}输出函数返回值
// {{函数名 参数1 参数2}}
// {{.字段名|函数名}} 以字段的值作为函数的参数
t6, _ = t6.Parse(`
{{test1}}
{{test2 "参数"}}
{{.UserName|test2}}
`)
t6.Execute(os.Stdout, Person{"003", "test3", 33, nil})
fmt.Println()

//条件判断
t7 := template.New("test")
t7.Funcs(template.FuncMap{"test3": test3})
// {{if 表达式}}{{else if}}{{else}}{{end}}
// if后面可以是一个条件表达式,可以是字符串或布尔值变量
// 注意if后面不能直接使用==来判断
t7, _ = t7.Parse(`
{{if 1}}
为真
{{else}}
为假
{{end}}

{{$a := 4}}
{{if $a|test3}}
$a=3
{{else}}
$a!=3
{{end}}
`)
t7.Execute(os.Stdout, nil)
fmt.Println()

//遍历
t8 := template.New("test")
// {{range 键,值 := 变量}}{{end}} 遍历对象
// {{with 变量}}{{end}} 指定当前操作的对象
t8, _ = t8.Parse(`
{{range $k, $v := .Contact}}
{{$k}} {{$v}}
{{end}}

{{with .Contact}}
{{range $k, $v := .}}
{{$k}} {{$v}}
{{end}}
{{end}}
`)
con := make(map[string]string)
con["qq"] = "123456"
con["tel"] = "13888888888"
t8.Execute(os.Stdout, Person{Contact: con})
fmt.Println()

//嵌套模板
t9 := template.New("test")
t9.Funcs(template.FuncMap{"test1": test1})
// {{define "模板名"}}模板内容{{end}} 定义模板
// {{template "模板名"}} 引入模板
// {{template "模板名" 函数}} 将函数中的值赋给模板中的{{.}}
t9, _ = t9.Parse(`
{{define "tp1"}} 我是模板1 {{end}}
{{define "tp2"}} 我是模板2 {{.}} {{end}}
{{define "tp3"}} {{template "tp1"}} {{template "tp2"}} {{end}}
{{template "tp1"}}
{{template "tp2" test1}}
{{template "tp3" test1}}
`)
t9.Execute(os.Stdout, nil)
fmt.Println()

//内置的模板函数
t10 := template.New("test")
t10.Funcs(template.FuncMap{"sum": sum})
t10, _ = t10.Parse(`
/*如果3为真,返回4,否则返回3*/
{{and 3 4}}

/*call后第一个参数的返回值必须是一个函数*/
{{call sum 1 3 5 7}}

/*转义文本中的html标签*/
{{"<br>"|html}}

/*返回Contact索引为qq的值*/
{{index .Contact "qq"}}

/*返回用js的escape处理后的文本*/
{{"?a=123&b=你好"|js}}

/*返回参数的长度值*/
{{"hello"|len}}

/*返回单一参数的布尔否定值*/
{{not 0}}

/*如果3为真,返回3,否则返回4*/
{{or 3 4}}

/*fmt.Sprint的别名*/
{{"你好"|print "世界"}}

/*fmt.Sprintf的别名*
{{"你好"|printf "%d %s" 123}}

/*fmt.Sprintln的别名*/
{{"你好"|println "世界"}}

/*url中get参数转义*/
{{"?q=关键字&p=1"|urlquery}}

/*等于*/
{{if eq 1 1}}
1=1
{{end}}

/*不等于*/
{{if ne 1 1}}
1!=1
{{end}}

/*小于*/
{{if lt 3 1}}
3<1
{{end}}

/*小于等于*/
{{if le 3 3}}
3<=3
{{end}}

/*大于*/
{{if gt 3 1}}
3>1
{{end}}

/*大于等于*/
{{if ge 3 3}}
3>=3
{{end}}
`);
con2 := make(map[string]string)
con2["qq"] = "123456"
con2["tel"] = "13888888888"
t10.Execute(os.Stdout, Person{Contact: con2})
}

package template

1
import "text/template"

template包实现了数据驱动的用于生成文本输出的模板。

如果要生成HTML格式的输出,参见html/template包,该包提供了和本包相同的接口,但会自动将输出转化为安全的HTML格式输出,可以抵抗一些网络攻击。

通过将模板应用于一个数据结构(即该数据结构作为模板的参数)来执行,来获得输出。模板中的注释引用数据接口的元素(一般如结构体的字段或者字典的键)来控制执行过程和获取需要呈现的值。模板执行时会遍历结构并将指针表示为'.'(称之为"dot")指向运行过程中数据结构的当前位置的值。

用作模板的输入文本必须是utf-8编码的文本。"Action"—数据运算和控制单位—由"和"界定;在Action之外的所有文本都不做修改的拷贝到输出中。Action内部不能有换行,但注释可以有换行。

经解析生成模板后,一个模板可以安全的并发执行。

下面是一个简单的例子,可以打印"17 of wool"。

1
2
3
4
5
6
7
8
9
type Inventory struct {
Material string
Count uint
}
sweaters := Inventory{"wool", 17}
tmpl, err := template.New("test").Parse("{{.Count}} of {{.Material}}")
if err != nil { panic(err) }
err = tmpl.Execute(os.Stdout, sweaters)
if err != nil { panic(err) }

更复杂的例子在下面。

text and spaces

虽然所有在{{}}`控制注解之外的文本会默认一分不差地复制到输出中,但是如果`{{`紧接着跟随减号和ASCII空格字符的话,那么`{{`之前的文本中的空白(空格、换行符、回车符、制表符)会被移除。对应的,`-}}表示移除之后文本中的空白。

例如上面例子,稍作修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"os"
"text/template"
)

type Inventory struct {
Material string
Count uint
}

func main(){
sweaters := Inventory{"wool", 17}
tmpl, err := template.New("test").Parse("{{.Count -}} items are made of {{- .Material}}")
if err != nil { panic(err) }
err = tmpl.Execute(os.Stdout, sweaters)
if err != nil { panic(err) }
}

执行结果:

1
17items are made ofwool%

Actions

下面是一个action(动作)的列表。"Arguments"和"pipelines"代表数据的执行结果,细节定义在后面

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
30
{{/* a comment */}}
注释,执行时会忽略。可以多行。注释不能嵌套,并且必须紧贴分界符始止,就像这里表示的一样。
{{- /* 去掉前后空白 */ -}}
//action的注释不会被输出,且必须在“{{}}”内,由“/*”和“*/”包含
{{pipeline}}
pipeline的值的默认文本表示会被拷贝到输出里。
{{if pipeline}} T1 {{end}}
如果pipeline的值为empty,不产生输出,否则输出T1执行结果。不改变dot的值。
Empty值包括false、0、任意nil指针或者nil接口,任意长度为0的数组、切片、字典。
{{if pipeline}} T1 {{else}} T0 {{end}}
如果pipeline的值为empty,输出T0执行结果,否则输出T1执行结果。不改变dot的值。
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
用于简化if-else链条,else action可以直接包含另一个if;等价于:
{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
{{range pipeline}} T1 {{end}}
pipeline的值必须是数组、切片、字典或者通道。
如果pipeline的值其长度为0,不会有任何输出;
否则dot依次设为数组、切片、字典或者通道的每一个成员元素并执行T1;
如果pipeline的值为字典,且键可排序的基本类型,元素也会按键的顺序排序。
{{range pipeline}} T1 {{else}} T0 {{end}}
pipeline的值必须是数组、切片、字典或者通道。
如果pipeline的值其长度为0,不改变dot的值并执行T0;否则会修改dot并执行T1。
{{template "name"}}
执行名为name的模板,提供给模板的参数为nil,如模板不存在输出为""
{{template "name" pipeline}}
执行名为name的模板,提供给模板的参数为pipeline的值。
{{with pipeline}} T1 {{end}}
如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot。
{{with pipeline}} T1 {{else}} T0 {{end}}
如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。

Arguments

参数代表一个简单的,由下面的某一条表示的值:

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
- go语法的布尔值、字符串、字符、整数、浮点数、虚数、复数,视为无类型字面常数,字符串不能跨行
- 关键字nil,代表一个go的无类型的nil值
- 字符'.'(句点,用时不加单引号),代表dot的值
- 变量名,以美元符号起始加上(可为空的)字母和数字构成的字符串,如:$piOver2和$;
执行结果为变量的值,变量参见下面的介绍
- 结构体数据的字段名,以句点起始,如:.Field;
执行结果为字段的值,支持链式调用:.Field1.Field2;
字段也可以在变量上使用(包括链式调用):$x.Field1.Field2;
- 字典类型数据的键名;以句点起始,如:.Key;
执行结果是该键在字典中对应的成员元素的值;
键也可以和字段配合做链式调用,深度不限:.Field1.Key1.Field2.Key2;
虽然键也必须是字母和数字构成的标识字符串,但不需要以大写字母起始;
键也可以用于变量(包括链式调用):$x.key1.key2;
- 数据的无参数方法名,以句点为起始,如:.Method;
执行结果为dot调用该方法的返回值,dot.Method();
该方法必须有1到2个返回值,如果有2个则后一个必须是error接口类型;
如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板执行者该错误;
方法可和字段、键配合做链式调用,深度不限:.Field1.Key1.Method1.Field2.Key2.Method2;
方法也可以在变量上使用(包括链式调用):$x.Method1.Field;
- 无参数的函数名,如:fun;
执行结果是调用该函数的返回值fun();对返回值的要求和方法一样;函数和函数名细节参见后面。
- 上面某一条的实例加上括弧(用于分组)
执行结果可以访问其字段或者键对应的值:
print (.F1 arg1) (.F2 arg2)
(.StructValuedMethod "arg").Field

Arguments可以是任何类型:如果是指针,在必要时会自动表示为指针指向的值;如果执行结果生成了一个函数类型的值,如结构体的函数类型字段,该函数不会自动调用,但可以在if等action里视为真。如果要调用它,使用call函数,参见下面。

Pipeline是一个(可能是链状的)command序列。Command可以是一个简单值(argument)或者对函数或者方法的(可以有多个参数的)调用:

1
2
3
4
5
6
7
Argument
执行结果是argument的执行结果
.Method [Argument...]
方法可以独立调用或者位于链式调用的末端,不同于链式调用中间的方法,可以使用参数;
执行结果是使用给出的参数调用该方法的返回值:dot.Method(Argument1, etc.);
functionName [Argument...]
执行结果是使用给定的参数调用函数名指定的函数的返回值:function(Argument1, etc.);

Pipelines

pipeline通常是将一个command序列分割开,再使用管道符'|'连接起来(但不使用管道符的command序列也可以视为一个管道)。在一个链式的pipeline里,每个command的结果都作为下一个command的最后一个参数。pipeline最后一个command的输出作为整个管道执行的结果。

command的输出可以是1到2个值,如果是2个后一个必须是error接口类型。如果error类型返回值非nil,模板执行会中止并将该错误返回给执行模板的调用者。

Variables

Action里可以初始化一个变量来捕获管道的执行结果。初始化语法如下:

1
$variable := pipeline

其中$variable是变量的名字。声明变量的action不会产生任何输出。

如果"range" action初始化了1个变量,该变量设置为迭代器的每一个成员元素,如果初始化了逗号分隔的2个变量:

1
range $index, $element := pipeline

这时,$index和$element分别设置为数组/切片的索引或者字典的键,以及对应的成员元素。注意这和go range从句只有一个参数时设置为索引/键不同!

一个变量的作用域只到声明它的控制结构("if"、"with"、"range")的"end"为止,如果不是在控制结构里声明会直到模板结束为止。子模板的调用不会从调用它的位置(作用域)继承变量。

模板开始执行时,$会设置为传递给Execute方法的参数,就是说,dot的初始值。

Examples

下面是一些单行模板,展示了pipeline和变量。所有都生成加引号的单词"output":

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{{"\"output\""}}
字符串常量
{{`"output"`}}
原始字符串常量
{{printf "%q" "output"}}
函数调用
{{"output" | printf "%q"}}
函数调用,最后一个参数来自前一个command的返回值
{{printf "%q" (print "out" "put")}}
加括号的参数
{{"put" | printf "%s%s" "out" | printf "%q"}}
玩出花的管道的链式调用
{{"output" | printf "%s" | printf "%q"}}
管道的链式调用
{{with "output"}}{{printf "%q" .}}{{end}}
使用dot的with action
{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
创建并使用变量的with action
{{with $x := "output"}}{{printf "%q" $x}}{{end}}
将变量使用在另一个action的with action
{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
以管道形式将变量使用在另一个action的with action

Functions

执行模板时,函数从两个函数字典中查找:首先是模板函数字典,然后是全局函数字典。一般不在模板内定义函数,而是使用Funcs方法添加函数到模板里。

预定义的全局函数如下:

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
30
31
32
and
函数返回它的第一个empty参数或者最后一个参数;
就是说"and x y"等价于"if x then y else x";所有参数都会执行;
or
返回第一个非empty参数或者最后一个参数;
亦即"or x y"等价于"if x then x else y";所有参数都会执行;
not
返回它的单个参数的布尔值的否定
len
返回它的参数的整数类型长度
index
执行结果为第一个参数以剩下的参数为索引/键指向的值;
如"index x 1 2 3"返回x[1][2][3]的值;每个被索引的主体必须是数组、切片或者字典。
print
即fmt.Sprint
printf
即fmt.Sprintf
println
即fmt.Sprintln
html
返回其参数文本表示的HTML逸码等价表示。
urlquery
返回其参数文本表示的可嵌入URL查询的逸码等价表示。
js
返回其参数文本表示的JavaScript逸码等价表示。
call
执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函数的参数;
如"call .X.Y 1 2"等价于go语言里的dot.X.Y(1, 2);
其中Y是函数类型的字段或者字典的值,或者其他类似情况;
call的第一个参数的执行结果必须是函数类型的值(和预定义函数如print明显不同);
该函数类型值必须有1到2个返回值,如果有2个则后一个必须是error接口类型;
如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板执行者该错误;

布尔函数会将任何类型的零值视为假,其余视为真。

下面是定义为函数的二元比较运算的集合:

1
2
3
4
5
6
eq      如果arg1 == arg2则返回真
ne 如果arg1 != arg2则返回真
lt 如果arg1 < arg2则返回真
le 如果arg1 <= arg2则返回真
gt 如果arg1 > arg2则返回真
ge 如果arg1 >= arg2则返回真

为了简化多参数相等检测,eq(只有eq)可以接受2个或更多个参数,它会将第一个参数和其余参数依次比较,返回下式的结果:

1
arg1==arg2 || arg1==arg3 || arg1==arg4 ...

(和go的||不一样,不做惰性运算,所有参数都会执行)

比较函数只适用于基本类型(或重定义的基本类型,如"type Celsius float32")。它们实现了go语言规则的值的比较,但具体的类型和大小会忽略掉,因此任意类型有符号整数值都可以互相比较;任意类型无符号整数值都可以互相比较;等等。但是,整数和浮点数不能互相比较。

Associated templates

每一个模板在创建时都要用一个字符串命名。同时,每一个模板都会和0或多个模板关联,并可以使用它们的名字调用这些模板;这种关联可以传递,并形成一个模板的名字空间。

一个模板可以通过模板调用实例化另一个模板;参见上面的"template" action。name必须是包含模板调用的模板相关联的模板的名字。

Nested template definitions

当解析模板时,可以定义另一个模板,该模板会和当前解析的模板相关联。模板必须定义在当前模板的最顶层,就像go程序里的全局变量一样。

这种定义模板的语法是将每一个子模板的声明放在"define"和"end" action内部。

define action使用给出的字符串常数给模板命名,举例如下:

1
2
3
4
`{{define "T1"}}ONE{{end}}
{{define "T2"}}TWO{{end}}
{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
{{template "T3"}}`

它定义了两个模板T1和T2,第三个模板T3在执行时调用这两个模板;最后该模板调用了T3。输出结果是:

1
ONE TWO

采用这种方法,一个模板只能从属于一个关联。如果需要让一个模板可以被多个关联查找到;模板定义必须多次解析以创建不同的*Template 值,或者必须使用Clone或AddParseTree方法进行拷贝。

可能需要多次调用Parse函数以集合多个相关的模板;参见ParseFiles和ParseGlob函数和方法,它们提供了简便的途径去解析保存在文件中的存在关联的模板。

一个模板可以直接调用或者通过ExecuteTemplate方法调用指定名字的相关联的模板;我们可以这样调用模板:

1
2
3
4
err := tmpl.Execute(os.Stdout, "no data needed")
if err != nil {
log.Fatalf("execution failed: %s", err)
}

或显式的指定模板的名字来调用:

1
2
3
4
err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed")
if err != nil {
log.Fatalf("execution failed: %s", err)
}
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

【模板标签】

模板标签用"{{"和"}}"括起来



【注释】

{{/* a comment */}}

使用“{{/*”和“*/}}”来包含注释内容



【变量】

{{.}}

此标签输出当前对象的值

{{.Admpub}}

表示输出Struct对象中字段或方法名称为“Admpub”的值。

当“Admpub”是匿名字段时,可以访问其内部字段或方法,比如“Com”:{{.Admpub.Com}} ,

如果“Com”是一个方法并返回一个Struct对象,同样也可以访问其字段或方法:{{.Admpub.Com.Field1}}

{{.Method1 "参数值1" "参数值2"}}

调用方法“Method1”,将后面的参数值依次传递给此方法,并输出其返回值。

{{$admpub}}

此标签用于输出在模板中定义的名称为“admpub”的变量。当$admpub本身是一个Struct对象时,可访问其字段:{{$admpub.Field1}}

在模板中定义变量:变量名称用字母和数字组成,并带上“$”前缀,采用符号“:=”进行赋值。

比如:{{$x := "OK"}} 或 {{$x := pipeline}}



【管道函数】

用法1:

{{FuncName1}}

此标签将调用名称为“FuncName1”的模板函数(等同于执行“FuncName1()”,不传递任何参数)并输出其返回值。

用法2:

{{FuncName1 "参数值1" "参数值2"}}

此标签将调用“FuncName1("参数值1", "参数值2")”,并输出其返回值

用法3:

{{.Admpub|FuncName1}}

此标签将调用名称为“FuncName1”的模板函数(等同于执行“FuncName1(this.Admpub)”,将竖线“|”左边的“.Admpub”变量值作为函数参数传送)并输出其返回值。



【条件判断】

用法1:

{{if pipeline}} T1 {{end}}

标签结构:{{if ...}} ... {{end}}

用法2:

{{if pipeline}} T1 {{else}} T0 {{end}}

标签结构:{{if ...}} ... {{else}} ... {{end}}

用法3:

{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}

标签结构:{{if ...}} ... {{else if ...}} ... {{end}}

其中if后面可以是一个条件表达式(包括管道函数表达式。pipeline即管道),也可以是一个字符窜变量或布尔值变量。当为字符窜变量时,如为空字符串则判断为false,否则判断为true。



【遍历】

用法1:

{{range $k, $v := .Var}} {{$k}} => {{$v}} {{end}}

range...end结构内部如要使用外部的变量,比如.Var2,需要这样写:$.Var2

(即:在外部变量名称前加符号“$”即可,单独的“$”意义等同于global)

用法2:

{{range .Var}} {{.}} {{end}}

用法3:

{{range pipeline}} T1 {{else}} T0 {{end}}

当没有可遍历的值时,将执行else部分。



【嵌入子模板】

用法1:

{{template "name"}}

嵌入名称为“name”的子模板。使用前,请确保已经用“{{define "name"}}子模板内容{{end}}”定义好了子模板内容。

用法2:

{{template "name" pipeline}}

将管道的值赋给子模板中的“.”(即“{{.}}”)



【子模板嵌套】

{{define "T1"}}ONE{{end}}

{{define "T2"}}TWO{{end}}

{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}

{{template "T3"}}

输出:

ONE TWO



【定义局部变量】

用法1:

{{with pipeline}} T1 {{end}}

管道的值将赋给该标签内部的“.”。(注:这里的“内部”一词是指被{{with pipeline}}...{{end}}包围起来的部分,即T1所在位置)

用法2:

{{with pipeline}} T1 {{else}} T0 {{end}}

如果管道的值为空,“.”不受影响并且执行T0,否则,将管道的值赋给“.”并且执行T1。





说明:{{end}}标签是if、with、range的结束标签。

【例子:输出字符窜】

{{"\"output\""}}

输出一个字符窜常量。


{{`"output"`}}

输出一个原始字符串常量

{{printf "%q" "output"}}

函数调用.(等同于:printf("%q", "output")。)

{{"output" | printf "%q"}}

竖线“|”左边的结果作为函数最后一个参数。(等同于:printf("%q", "output")。)

{{printf "%q" (print "out" "put")}}

圆括号中表达式的整体结果作为printf函数的参数。(等同于:printf("%q", print("out", "put"))。)


{{"put" | printf "%s%s" "out" | printf "%q"}}

一个更复杂的调用。(等同于:printf("%q", printf("%s%s", "out", "put"))。)

{{"output" | printf "%s" | printf "%q"}}

等同于:printf("%q", printf("%s", "output"))。

{{with "output"}}{{printf "%q" .}}{{end}}

一个使用点号“.”的with操作。(等同于:printf("%q", "output")。)

{{with $x := "output" | printf "%q"}}{{$x}}{{end}}

with结构,定义变量,值为执行管道函数之后的结果(等同于:$x := printf("%q", "output")。)

{{with $x := "output"}}{{printf "%q" $x}}{{end}}

with结构中,在其它动作中使用定义的变量

{{with $x := "output"}}{{$x | printf "%q"}}{{end}}

同上,但使用了管道。(等同于:printf("%q", "output")。)


===============【预定义的模板全局函数】================

【and】

{{and x y}}

表示:if x then y else x

如果x为真,返回y,否则返回x。等同于Golang中的:x && y

【call】

{{call .X.Y 1 2}}

表示:dot.X.Y(1, 2)

call后面的第一个参数的结果必须是一个函数(即这是一个函数类型的值),其余参数作为该函数的参数。

该函数必须返回一个或两个结果值,其中第二个结果值是error类型。

如果传递的参数与函数定义的不匹配或返回的error值不为nil,则停止执行。

【html】

转义文本中的html标签,如将“<”转义为“<”,“>”转义为“>”等

【index】

{{index x 1 2 3}}

返回index后面的第一个参数的某个索引对应的元素值,其余的参数为索引值

表示:x[1][2][3]

x必须是一个map、slice或数组

【js】

返回用JavaScript的escape处理后的文本



【len】

返回参数的长度值(int类型)

【not】

返回单一参数的布尔否定值。


【or】

{{or x y}}

表示:if x then x else y。等同于Golang中的:x || y

如果x为真返回x,否则返回y。


【print】

fmt.Sprint的别名



【printf】

fmt.Sprintf的别名


【println】

fmt.Sprintln的别名


【urlquery】

返回适合在URL查询中嵌入到形参中的文本转义值。(类似于PHP的urlencode)

=================【布尔函数】===============

布尔函数对于任何零值返回false,非零值返回true。

这里定义了一组二进制比较操作符函数:



【eq】

返回表达式“arg1 == arg2”的布尔值

【ne】

返回表达式“arg1 != arg2”的布尔值

【lt】

返回表达式“arg1 < arg2”的布尔值

【le】

返回表达式“arg1 <= arg2”的布尔值

【gt】

返回表达式“arg1 > arg2”的布尔值

【ge】

返回表达式“arg1 >= arg2”的布尔值

对于简单的多路相等测试,eq只接受两个参数进行比较,后面其它的参数将分别依次与第一个参数进行比较,

{{eq arg1 arg2 arg3 arg4}}

即只能作如下比较:

arg1==arg2 || arg1==arg3 || arg1==arg4 ...