template package (godoc 翻译)
template 包
概述(Overview)
template 包实现了数据驱动模板用于生成文本输出。
要生成HTML输出,请参阅html/template包,它具有与此包相同的接口,但会自动保护HTML输出免受某些攻击。
通过将模板应用于数据结构来执行模板。模板中的注释引用数据结构的元素(通常是结构体的字段,或map中的key)来控制执行,导出要显示的值。模板的执行遍历结构体,并设置游标,由句点”.”表示,并称为“点”,结构体当前位置的值作为执行所得的值。
模板的输入文本是任意格式的utf-8编码的文本。“Actions”--数据计算或控制结构--由”{{”和”}}”分隔,Actions之外的文本被原封不动地复制到输出。除了原始字符串,actions不能跨行,但是注释是可以的。
一旦解析,模板可以安全地并行执行。
这是一个简单的例子,打印”17 items are made of wool”
type Inventory struct {
Material string
Count uint
}
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) }
下面有更复杂的例子。
文本和空格 Text and spaces
默认情况下,当版本执行时,动作之间的所有文字将逐字复制。例如,当程序运行时,上例中的字符串”items are made of”在标准输出中出现。
然而,为了帮助格式化模板源代码,如果一个action的左分隔符(默认是”{{”)紧跟着一个减号和ASCII空格符(“{- ”),尾随前面文本(“{{”之前的)的空格都将被去除。类似地,如果右分隔符”}}”前面有空格和减号(“ -}}”),则所有前导的空格都将从紧跟的文本中去除。在这些修剪标记中(trim markers),ASCII码空格必须存在, "{{-3}}"被解析为包含-3的action。(“{{3-}}”,编译报错, unexpected bad number syntax: "23-" in command)
例如,当执行如下源的模板时
"{{23 -}} < {{- 45}}"
生成的输出将是
“23<45”
对于此修剪(trim),空白符的定义与Go中相同:空格,水平制表符,回车符和换行符中的定义相同。
Actions
以下是action列表。”Arguments”和”pipelines”是数据计算,在下面的相应部分中详细定义。
{{/* a comment */}}
A comment; discarded. May contain newlines.
Comments do not nest and must start and end at the
delimiters, as shown here.
注释,在输出中被丢弃。可以包含换行符
注释不能嵌套,必须在分隔符处开始和结束。
(补充,例如,`comments example {{ /*this is a comment*/}}`,”{{”和”/*”之间有空格,编译将报错,unexpected "/" in command
模板只支持 /* */ 形式的注释,不支持Go语言中 //前导的单行注释
)
{{pipeline}}
The default textual representation (the same as would be
printed by fmt.Print) of the value of the pipeline is copied
to the output.
管道值的默认文本表示(与fmt.Print的打印值相同)被复制到输出。
{{if pipeline}} T1 {{end}}
If the value of the pipeline is empty, no output is generated;
otherwise, T1 is executed. The empty values are false, 0, any
nil pointer or interface value, and any array, slice, map, or
string of length zero.
Dot is unaffected.
如果管道的值为空,则不会生成输出。
否则执行T1。 空值可以是 false,0,任意的nil指针或接口值,以及任何数组,切片,
map或长度为0的字符串。
点不受影响
{{if pipeline}} T1 {{else}} T0 {{end}}
If the value of the pipeline is empty, T0 is executed;
otherwise, T1 is executed. Dot is unaffected.
如果管道的值为空,T0被执行
否则,T1被执行。
点不受影响。
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
To simplify the appearance of if-else chains, the else action
of an if may include another if directly; the effect is exactly
the same as writing
{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
为了简化if-else链的外观,任何if的else action可以直接包含另一个if;效果与如下
写法相同:{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
{{range pipeline}} T1 {{end}}
The value of the pipeline must be an array, slice, map, or channel.
If the value of the pipeline has length zero, nothing is output;
otherwise, dot is set to the successive elements of the array,
slice, or map and T1 is executed. If the value is a map and the
keys are of basic type with a defined order ("comparable"), the
elements will be visited in sorted key order.
管道的值必须是数组,切片,map或通道,如果管道值的长度为0,则不输出任何值。
否则,将点设置为数组、切片、map的相继元素,T1被执行。如果值是map,并且它的key是有定义顺序(可比较)的基础类型,元素以按key排序的顺序访问。
{{range pipeline}} T1 {{else}} T0 {{end}}
The value of the pipeline must be an array, slice, map, or channel.
If the value of the pipeline has length zero, dot is unaffected and
T0 is executed; otherwise, dot is set to the successive elements
of the array, slice, or map and T1 is executed.
管道的值必须是数组,切片,map或通道。如果管道值的长度为0,点不受影响,T0被执行;否则点被设置为数组、切片、map的相继值,T1被执行。
{{template "name"}}
The template with the specified name is executed with nil data.
具有指定名称的模板将使用nil数据执行。
{{template "name" pipeline}}
The template with the specified name is executed with dot set
to the value of the pipeline.
具有指定名称的模板将使用点设置值到管道来执行。
{{block "name" pipeline}} T1 {{end}}
A block is shorthand for defining a template
{{define "name"}} T1 {{end}}
and then executing it in place
{{template "name" .}}
The typical use is to define a set of root templates that are
then customized by redefining the block templates within.
块是用于定义模板的简写:{{define "name"}} T1 {{end}}
然后在该位置执行它。 {{template "name" .}}
典型的用法是定义一组根模板,然后通过重新定义块模板进行定制。
{{with pipeline}} T1 {{end}}
If the value of the pipeline is empty, no output is generated;
otherwise, dot is set to the value of the pipeline and T1 is
executed.
如果管道的值为空,则不会生成输出。
否则,点设置为管道的值,T1被执行。
{{with pipeline}} T1 {{else}} T0 {{end}}
If the value of the pipeline is empty, dot is unaffected and T0
is executed; otherwise, dot is set to the value of the pipeline
and T1 is executed.
如果管道的值为空,则点不受影响,T0被执行;
否则点设置为管道的值,并执行T1
参数 Arguments
An argument is a simple value, denoted by one of the following.
参数是一个简单的值,用下面的其中之一来表示。
- A boolean, string, character, integer, floating-point, imaginary
or complex constant in Go syntax. These behave like Go's untyped
Constants.
一个布尔值,字符串,字符,整数,浮点数,虚数或Go语法中的复数常量。这些行为像Go的无类型常量。
- The keyword nil, representing an untyped Go nil.
关键词nil,表示一个无类型的go nil
- The character '.' (period):
.
The result is the value of dot.
字符. 结果是点的值。
- A variable name, which is a (possibly empty) alphanumeric string
preceded by a dollar sign, such as
$piOver2
or
$
The result is the value of the variable.
Variables are described below.
一个变量的名称,它是一个(可能为空的)字符数字字符串,前面有个美元符号,如
$piOver2
要么 $
结果是变量的值。变量如下所述。
- The name of a field of the data, which must be a struct, preceded
by a period, such as
.Field
The result is the value of the field. Field invocations may be
chained:
.Field1.Field2
Fields can also be evaluated on variables, including chaining:
$x.Field1.Field2
数据的一个字段的名称,它必须是一个结构体,前面有一个. 如
.Field
结构是字段的值。Field调用可以是链式的
.Filed1.Field2
字段也可以对变量进行计算,包括链式
$x.Field1.Field2
- The name of a key of the data, which must be a map, preceded
by a period, such as
.Key
The result is the map element value indexed by the key.
Key invocations may be chained and combined with fields to any
depth:
.Field1.Key1.Field2.Key2
Although the key must be an alphanumeric identifier, unlike with
field names they do not need to start with an upper case letter.
Keys can also be evaluated on variables, including chaining:
$x.key1.key2
数据键的名称,必须是一个map,前面有一个.如
.Key
结果是按键索引的map元素值
Key调用可以是链式的,与任意深度的字段组合
.Field1.Key1.Field2.Key2
虽然key必须是字母数字标识符,不同于字段名称,不需要以大写字母开头。
键也可以对变量进行计算,包括链式:
$x.key1.key2
- The name of a niladic method of the data, preceded by a period,
such as
.Method
The result is the value of invoking the method with dot as the
receiver, dot.Method(). Such a method must have one return value (of
any type) or two return values, the second of which is an error.
If it has two and the returned error is non-nil, execution terminates
and an error is returned to the caller as the value of Execute.
Method invocations may be chained and combined with fields and keys
to any depth:
.Field1.Key1.Method1.Field2.Key2.Method2
Methods can also be evaluated on variables, including chaining:
$x.Method1.Field
数据的方法名称,前面有一个.
.Method
结果是使用点作为接收器调用方法的值,dot.Method()
这样的方法必须有一个返回值(任何类型)或两个返回值,其中第二个是error
如果有两个返回值,返回的error不是nil,执行终止。
并且error被返回给调用者作为Execute的值
方法调用可以链接,并与字段和键组合到任何深度:
.Field1.Key1.Method1.Field2.Key2.Method2
方法也可以对变量进行计算,包括链式:
$x.Method1.Field
- The name of a niladic function, such as
fun
The result is the value of invoking the function, fun(). The return
types and values behave as in methods. Functions and function
names are described below.
一个niladic函数的名称,例如
fun
结果是调用fun()的值,返回的类型和值与方法一样。函数和函数的名称如下所述。
- A parenthesized instance of one the above, for grouping. The result
may be accessed by a field or map key invocation.
print (.F1 arg1) (.F2 arg2)
(.StructValuedMethod "arg").Field
上述一个的括号化实例,用于分组。结果可以通过字段或map键调用来访问。
Print(.F1 arg1)(.F2 arg2)
(.StructValuedMethod “arg”).Field
参数可以评估任何类型,如果它们是指针,则在需要时,实现将自动指向基本类型。如果评估产生函数值,例如struct的函数值字段,则该函数不会自动调用,但它可以用作if动作等的真值。要调用它,请使用下面定义的call函数。
Pipelines
管道可能是命令的链式序列。命令是一个简单的值(参数)或函数或方法调用,可以有多个参数。
Argument
The result is the value of evaluating the argument.
.Method [Argument...]
The method can be alone or the last element of a chain but,
unlike methods in the middle of a chain, it can take arguments.
The result is the value of calling the method with the
arguments:
dot.Method(Argument1, etc.)
functionName [Argument...]
The result is the value of calling the function associated
with the name:
function(Argument1, etc.)
Functions and function names are described below.
管道可以用管道字符”|”分隔一系列命令来链接。在链式管道中,每个命令的结果作为下一个命令的最后参数传递。管道中最后一个命令的输出是管道的值。
命令的输出可以是一个或两个值,其中第二个值是error类型。如果第二个值存在并计算为非零,则执行终止并将错误返回给Execute的调用方。
Variables
Action内的管道可以初始化变量来捕获结果。初始化语法如下:
$variable := pipeline
其中$variable是变量的名称。声明变量的操作不产生输出。
如果range action初始化变量,则将该变量设置为迭代的连续元素。此外,range可以声明两个变量,用逗号分隔:
range $index,$element := pipeline
在这种情况下,$index和$element分别设置为数组或切片的索引,或map的key,和连续的元素值。注意,如果只有一个变量,它被分配了元素,这与go range 子句中的惯例相反。
变量的作用域扩展到控制结构(if with range)的end action,如果没有这样的控制结构,则扩展到模板的end。模板调用不会从调用点继承变量。
当执行开始时,$被设置为传递给Execute的数据参数,即点的起始值。
Examples
以下是一些管道和变量的一行示例模板。所有产生引用的词”output”
{{"\"output\""}}
A string constant.
{{`"output"`}}
A raw string constant.
{{printf "%q" "output"}}
A function call.
{{"output" | printf "%q"}}
A function call whose final argument comes from the previous
command.
{{printf "%q" (print "out" "put")}}
A parenthesized argument.
{{"put" | printf "%s%s" "out" | printf "%q"}}
A more elaborate call.
{{"output" | printf "%s" | printf "%q"}}
A longer chain.
{{with "output"}}{{printf "%q" .}}{{end}}
A with action using dot.
{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
A with action that creates and uses a variable.
{{with $x := "output"}}{{printf "%q" $x}}{{end}}
A with action that uses the variable in another action.
{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
The same, but pipelined.
Functions
在执行过程中,函数在两个函数map中查找:首先在模板中,然后在全局函数map中。默认情况下,在模板中没有定义函数,但可以使用Funcs方法来添加它们。
预定于的全局函数命名如下:
and
Returns the boolean AND of its arguments by returning the
first empty argument or the last argument, that is,
"and x y" behaves as "if x then y else x". All the
arguments are evaluated.
call
Returns the result of calling the first argument, which
must be a function, with the remaining arguments as parameters.
Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where
Y is a func-valued field, map entry, or the like.
The first argument must be the result of an evaluation
that yields a value of function type (as distinct from
a predefined function such as print). The function must
return either one or two result values, the second of which
is of type error. If the arguments don't match the function
or the returned error value is non-nil, execution stops.
html
Returns the escaped HTML equivalent of the textual
representation of its arguments.
index
Returns the result of indexing its first argument by the
following arguments. Thus "index x 1 2 3" is, in Go syntax,
x[1][2][3]. Each indexed item must be a map, slice, or array.
js
Returns the escaped JavaScript equivalent of the textual
representation of its arguments.
len
Returns the integer length of its argument.
not
Returns the boolean negation of its single argument.
or
Returns the boolean OR of its arguments by returning the
first non-empty argument or the last argument, that is,
"or x y" behaves as "if x then x else y". All the
arguments are evaluated.
An alias for fmt.Sprint
printf
An alias for fmt.Sprintf
println
An alias for fmt.Sprintln
urlquery
Returns the escaped value of the textual representation of
its arguments in a form suitable for embedding in a URL query.
布尔函数取任何零值为false,非零值为true。
还有一组定义为函数的二值比较运算符:
eq
Returns the boolean truth of arg1 == arg2
ne
Returns the boolean truth of arg1 != arg2
lt
Returns the boolean truth of arg1 < arg2
le
Returns the boolean truth of arg1 <= arg2
gt
Returns the boolean truth of arg1 > arg2
ge
Returns the boolean truth of arg1 >= arg2
对于简单的多路相等测试,eq(仅有)接受两个或多个参数,并将第二个和后续的参数与第一个参数比较,效果上等同于
arg1==arg2 || arg1==arg3 || arg1==arg4 ...
(Unlike with || in Go, however, eq is a function call and all the arguments will be evaluated.)
(与Go中的||不同,eq是一个函数调用,所有的参数都将被计算)
比较函数只适用于基本类型(或称命名的基本类型,例如 type Celsius float32)。它们实现了用于比较值的Go规则,不同之处在于忽略大小和精确类型,因此可以将任何整数值,有符号或无符号的,与其他整数值进行比较。(用算术值进行比较,而不是为模式,所以所有负整数都小于所有无符号整数)。但是像通常一样,可能不会将int与float32等比较。
Associated templates关联模板
每个模板由创建时指定的字符串命名。此外,每个模板与零个或多个其他模板相关联,这可能是由名称引发的。这些关联是可传递的,并形成模板的命名空间。
模块可以使用模板调用实例化另一个关联的模板;请参阅上述模板action的说明。该名称必须是与包含该调用的模板相关联的模板。
Nested template definitions
解析模板时,可以定义另一个模板,并与要解析的模板相关联。模板定义必须出现在模板的顶层,就像Go程序的全局变量一样。
这种定义的语法是使用”define”和”end”action来包围每个模板的声明。
define action通过提供字符串常量来命名正在创建的模板。这是一个简单的例子:
`{{define "T1"}}ONE{{end}}
{{define "T2"}}TWO{{end}}
{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
{{template "T3"}}`
这定义了两个模板,T1和T2,还有第三个模板T3,当T3执行时调用T1、T2。最后调用T3,。如果执行此模板将生成文本:
ONE TWO
通过构造,模板可以仅驻留在一个关联模板中。如果使一个模板可以从多个关联模板中可寻址是必要的,那么模板定义必须被解析多次来创建不同的*Template值,或者必须使用Clone或AddParseTree方法复制。
Parse可能会被调用多次来组合各种关联的模板;请参阅ParseFiles和ParseGlob函数和方法来简单地解析存储在文件中的相关模板。
A template may be executed directly or through ExecuteTemplate, which executes an associated template identified by name. To invoke our example above, we might write,
模板可以直接执行或通过ExecuteTemplate执行,ExecuteTemplate执行由名称标识的关联模板。为了引用我们上面的例子,我们可以写:
err := tmpl.Execute(os.Stdout, "no data needed")
if err != nil {
log.Fatalf("execution failed: %s", err)
}
or to invoke a particular template explicitly by name,
err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed")
if err != nil {
log.Fatalf("execution failed: %s", err)
}