go标准库之template
templates包定义了数据驱动的文本输出。生成html文件的模板在html/template包下面。模板使用插值语法{{.var}}格式,也可以使用一些流程控制,例如判断if else、循环range还可以使用一些函数,包括内建函数和自定义函数。
第一个模板实例
func test1() {
name := "zs"
// {{.}} 表示占位一个变量
templateStr := "Hello,{{.}}"
// test为模板名称
t := template.New("test")
t2, err := t.Parse(templateStr)
if err != nil {
log.Fatal(err)
}
t2.Execute(os.Stdout, name) // Hello,zs
}
也可以是结构体
package main
import (
"os"
"text/template"
)
type Person struct {
Name string
Age int
}
func main() {
ghz := Person{"ghz", 80}
muban := "hello, {{.Name}}, Your age {{.Age}}"
tmpl, err := template.New("test").Parse(muban)
if err != nil {
panic(err)
}
err = tmpl.Execute(os.Stdout, ghz)
if err != nil {
panic(err)
}
}
运行结果
hello, ghz, Your age 80
html模板
定义一个HTML文件
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test golang template</title>
</head>
<body>
{{.}}
</body>
</html>
定义一个HttpServer
package main
import (
"html/template"
"net/http"
)
func tmpl(w http.ResponseWriter, r *http.Request) {
t1, err := template.ParseFiles("test.html")
if err != nil {
panic(err)
}
t1.Execute(w, "hello world")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/tmpl", tmpl)
server.ListenAndServe()
}
客户端访问
http://localhost:8080/tmpl
运行结果
hello,ghz
文本和空格
模板引擎在进行替换的时候,是完全按照文本格式进行替换的。除了需要评估和替换的地方,所有的行分隔符、空格等等空白都原样保留。所以,对于要解析的内容,不要随意缩进、随意换行。
例如:
{{23}} < {{45}} -> 23 < 45
{{23}} < {{- 45}} -> 23 <45
{{23 -}} < {{45}} -> 23< 45
{{23 -}} < {{- 45}} -> 23<45 // 把23后面的空格与35左边的空格去掉
去掉后空格
xxxx -}},去掉前空格{{- xxxx
模板注释
注释方式:{{/* a comment */}}。
注释后的内容不会被引擎进行替换。但需要注意,注释行在替换的时候也会占用行,所以应该去除前缀和后缀空白,否则会多一空行。
{{- /* a comment without prefix/suffix space */}}
{{/* a comment without prefix/suffix space */ -}}
{{- /* a comment without prefix/suffix space */ -}}
管道pipeline
管道就是一系列命令的链式调用。当然,也可以是一个命令,例如:计算表达式的值{{.}}、{{.Name}},或者是一个函数调用或者方法调用。
可以使用管道符号|链接多个命令,用法和unix下的管道类似:|前面的命令将运算结果(或返回值)传递给后一个命令的最后一个位置。
需要注意的是,并非只有使用了
|才是pipeline。Go template中,pipeline的概念是传递数据,只要能产生数据的,都是pipeline。
下面是Pipeline的几种示例,它们都输出"output":
{{`"output"`}}
{{printf "%q" "output"}}
{{"output" | printf "%q"}}
{{printf "%q" (print "out" "put")}}
{{"put" | printf "%s%s" "out" | printf "%q"}}
{{"output" | printf "%s" | printf "%q"}}
可以在HTML中测试
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test golang template</title>
</head>
<body>
{{`"output"`}} <br>
{{printf "%q" "output"}}<br>
{{"output" | printf "%q"}}<br>
{{printf "%q" (print "out" "put")}}<br>
{{"put" | printf "%s%s" "out" | printf "%q"}}<br>
{{"output" | printf "%s" | printf "%q"}}<br>
</body>
</html>
运行结果
"output"
"output"
"output"
"output"
"output"
"output"
变量
变量的语法
// 未定义过的变量
$var := pipeline
// 已定义过的变量
$var = pipeline
例如
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test golang template</title>
</head>
<body>
{{$Name := "tom"}}
{{$Name = "kite"}}
{{$Name}}<br>
{{$len := (len "hello,ghz")}}
{{$len}}
</body>
</html>
运行结果
kite
9
条件判断
语法
{{if pipeline}} T1 {{end}}
{{if pipeline}} T1 {{else}} T0 {{end}}
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
pipeline为false的情况是各种数据对象的0值:数值0,指针或接口是nil,数组、slice、map或string则是len为0。
可以使用如下运算符表达式
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
实例
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test golang template</title>
</head>
<body>
{{$Age := 18}}
{{if (ge $Age 18)}}
<h3>你已经成年!</h3>
{{else}}
<h3>你还未成年!</h3>
{{end}}
</body>
</html>
运行结果
你已经成年!
循环迭代
语法
{{range pipeline}} T1 {{end}}
{{range pipeline}} T1 {{else}} T0 {{end}}
range可以迭代slice、数组、map或channel。迭代的时候,会设置"."为当前正在迭代的元素。对于第一个表达式,当迭代对象的值为0值时,则range直接跳过,就像if一样。对于第二个表达式,则在迭代到0值时执行else语句。
实例演示
go代码
func tmpl(w http.ResponseWriter, r *http.Request) {
t1, err := template.ParseFiles("test.html")
if err != nil {
panic(err)
}
s := []string{"多课网", "golang 教程", "老郭"}
t1.Execute(w, s)
}
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test golang template</title>
</head>
<body>
{{range $x := . -}}
{{println $x}}
{{- end}}
</body>
</html>
运行结果
多课网 golang 教程 老郭
with...end
with用来设置"."的值,语法如下:
{{with pipeline}} T1 {{end}}
{{with pipeline}} T1 {{else}} T0 {{end}}
对于第一种格式,当pipeline不为0值的时候,点"."设置为pipeline运算的值,否则跳过。对于第二种格式,当pipeline为0值时,执行else语句块,否则"."设置为pipeline运算的值,并执行T1。
实例演示
{{with "多课网-golang-老郭"}}{{println .}}{{end}}
运行结果
多课网-golang-老郭
内置函数
and
返回第
一个空参数或最后一个参数返回其参数的布尔值 AND ,即
“and x y”表现为“if x then y else x”。
评估所有参数。
call
返回调用第一个参数的结果,该参数
必须是一个函数,其余参数作为参数。
因此,“call .XY 1 2”在 Go 表示法中是 dot.XY(1, 2),其中
Y 是函数值字段、映射条目等。
第一个参数必须是
产生函数类型值的评估结果(不同于
预定义的函数,如打印)。该函数必须
返回一个或两个结果值,其中第二个
是类型错误。如果参数与函数不匹配
或返回的错误值为非零,则执行停止。
html
返回等效
于其参数文本表示的转义 HTML 。此功能
在 html/template 中不可用,但有一些例外。
index
返回通过
以下参数对其第一个参数进行索引的结果。因此,在 Go 语法中,“索引 x 1 2 3”是
x[1][2][3]。每个索引项必须是映射、切片或数组。
slice
slice 返回其第一个参数被
其余参数切片的结果。因此,"slice x 1 2" 在 Go 语法中是 x[1:2],
而 "slice x" 是 x[:],"slice x 1" 是 x[1:],
是 x[1:2:3]。第一个参数必须是字符串、切片或数组。
js
返回转义的 JavaScript 等效
于其参数的文本表示。
len
返回其参数的整数长度。
not
返回其单个参数的布尔否定。
or
通过返回第
一个非空参数或最后一个参数来返回其参数的布尔 OR ,即
“or x y”表现为“if x then x else y”。
评估所有参数。
print
fmt.Sprint
的别名
printf fmt.Sprintf
的别名
println fmt.Sprint的别名
urlquery
以适合嵌入 URL 查询的形式
返回其参数的文本表示的转义值。
此功能在 html/template 中不可用,但有一些
例外。
嵌套template:define和template
define可以直接在待解析内容中定义一个模板,这个模板会加入到common结构组中,并关联到关联名称上。
{{template "name"}}
{{template "name" pipeline}}
{{define "name"}}
实例演示
假设我们有一个header.html、footer.html和index.html,index.html包含header.html和footer.html
header.html
{{define "header"}}
<head>
<title>{{.Title}}</title>
</head>
{{end}}
go code
package main
import (
"html/template"
"net/http"
)
func tmpl(w http.ResponseWriter, r *http.Request) {
t1, err := template.ParseFiles("templates/index.html", "templates/header.html", "templates/footer.html")
if err != nil {
panic(err)
}
t1.Execute(w, nil)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/tmpl", tmpl)
server.ListenAndServe()
}
运行结果
这是header
首页...
这是footer