golang text/template的详细说明

概述

text/template实现基于数据的文本化输出。功能和jsp、blade.php(laravel)一样,用于动态生成文件,只不过golang用于生产HTML的模块为html/template1

运行过程

将template模板应用于结构化的数据,使用注解语法引用数据结构中的元素(struct中的feild或map中的key)并显示它们的值。template在执行过程中遍历数据结构并且设置当前光标(英文句号“.”标识)标识当前位置的元素(值)

一旦解析,模板可以安全地并行执行,但是如果并行执行共享Writer,则输出可以是交错的。

要求

template的文本必须为UTF-8编码。注解语法必须由“{{”和“}}”分隔,不在“{{”和“}}”的文本原样输出。一般来说注解语法不用另起一行,可以和非注解文本同行,不过如果是动态注释的话,注解语法还是建议另起一行。

遍历struct

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) }

上面的例子中模板test变量sweaters中的Count和Material域,“.Count”中的“.”标识sweaters根元素

执行结果

➜  template git:(master) ✗ go run text_template.go 
17 items are made of wool%    

text 和spaces

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

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

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) }
}

执行结果:

➜  template git:(master) ✗ go run text_template.go
17items are made ofwool% 

Actions

以下pipeline是对数据的假设
注释

{{/* 注释 */}}
{{- /* 去掉前后空白 */ -}}
	//action的注释不会被输出,且必须在“{{}}”内,由“/*”和“*/”包含

文本化输出

{{pipeline}}
//pipeline值的文本化表示被复制到输出

判断结构
if

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

如果pipeline为空(空字符、0、false、nil指针,nil接口, map或slice或array长度为0),无输出
if … else …

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

if…elseif …

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

循环结构

{{range pipeline}} T1 {{end}}

pipeline的必须为map、array、slice或channel。如果pipeline长度为0,无输出。如果长度大于0,则T1执行,“.”被设置为当前成功遍历的元素。如果pipeline为map并且key是可比较的,那么元素按照排序后的key值被访问

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

pipeline的必须为map、array、slice或channel。如果pipeline长度为0, 执行T0。否则执行T1。

模板嵌套

{{template "name"}}

执行指定模板name, 无任何数据传入

  {{template "name" pipeline}}

执行指定模板name, pipeline数据传入

{{block "name" pipeline}} T1 {{end}}

定义模板name并执行模板,传入数据pipeline

with

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

如果pipeline不为空,那么执行T1, 并将光标“.” 设置为pipeline

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

如果pipeline不为空,那么执行T1, 并将光标“.” 设置为pipeline;否则,执行T0, 光标“.”不受影响

Arguments

-  布尔型、字符串型、字符、整数、浮点型、虚数或负数和在go语法一样不变,表现和Go的无类型常量一样
- nil和Go的无类型nil一样
- “.”代表当前光标的值
- 变量名前面使用"$"符,例如
	$piOver2
  
- struct的数据根据域(字段)访问,例如
	.Field
  支持链式调用:
    .Field1.Field2
  数据域可以保持在变量中,所以同时支持下面写法:
    $x.Field1.Field2
    
- map数据根据key来访问,例如:
	.Key
  支持链式访问:
    .Field1.Key1.Field2.Key2
 字典keys同样支持变量存储后访问:
    $x.key1.key2
    
- 为方法的调用,例如
	.Method
    结果是以调用方法的值使用“.”作为接收器,dot.Method(). Mehod必须有一个或2个放回值
    第二个返回值为error类别,如果error不为空,执行中断,错误返回作为执行结果。方法调用支持链式操作:
     .Field1.Key1.Method1.Field2.Key2.Method2
  变量方式:
    $x.Method1.Field
    
- 函数调用:
	fun
- 组合调用:
	print (.F1 arg1) (.F2 arg2)
	(.StructValuedMethod "arg").Field

Pipeline

一个pipeline可能是链式的命令序列。一个命令可以是一个参数值、或一次函数调用、或一次方法调用。方法调用和函数调用可能有多个参数。

Argument
	结果就是参数的值
.Method [Argument...]
	method可以是单独的或者是链式调用的最后一个而不是链式调用的中间元素,这样才能获取参数
	结果就是使用参数调用method:
		dot.Method(Argument1, etc.)
functionName [Argument...]
	使用参数调用方法:
		function(Argument1, etc.)

通过用管道字符“|”分隔一系列命令,可以“链接”管道。 在链式管道中,每个命令的结果将作为以下命令的最后一个参数传递。 管道中最终命令的输出是管道的值。

命令的输出将是一个值或两个值,第二个值具有类型错误。 如果存在第二个值并且计算结果为非nil,则执行终止,并将错误返回给Execute的调用者。

Variables

在一次action内,pipeline可以使用变量捕获结果

$variable := pipeline

如果在一个range action内使用变量,可以给成功迭代的元素设置变量:

range $index,$element := range pipeline

变量的作用范围在它生命的控制结构内,直到“end”action结束.如果不在控制结构内生命的变量,直到template结束。

当template开始执行时,$变量被默认设置成传递个Execute函数的数据参数,也就是“.”光标的开始值

Pilelines和Variables例子

{{"\"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"}}
	链式调用.
{{with "output"}}{{printf "%q" .}}{{end}}
	使用with action的调用,.为pipeline的值
{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
	with action 创建变量和使用变量
{{with $x := "output"}}{{printf "%q" $x}}{{end}}
	with action 创建变量并在作用范围内在另一action使用变量
{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
	with action 创建变量和使用管道“|”

Functions

在执行期间,函数在2个函数字典查找:首先查找template函数字典,然后查找全局函数字典。默认情况下,template函数字典没有函数,不过提供了Funcs方法设置template函数字典。

预定义的全局函数有:

and		返回bool值,例如 and x y

call		第一个参数为调用的函数,其他为该函数的参数,例如 call .X.Y 1 2,
		等效dot.X.Y(1, 2) ,该函数一样必须由1个或2个返回值,第二个为error类型

html 	返回参数的文本化表示的HTML。 此功能不可用
		在html / template中,有一些异常。

index 	例如, index x 1 2 3 。  表示x[1][2][3]

js		返回参数的文本化表示的javascript

len		返回参数的长度

not 		返回参数的否定值

or		或运算,例如 or x y

print
		fmt.Sprint别名
printf
		fmt.Sprintf别名
println
		fmt.Sprintln别名
urlquery 	
		返回文本表示形式的转义值, 它的参数以适合嵌入URL查询的形式出现。

上面的bool函数把任何零值当做false,非零值当做true

比较函数:

eq		等于	操作符:arg1 == arg2

ne  		不等于	操作符:arg1 != arg2

lt		小于	操作符	arg1 < arg2

le		小于等于	操作符	arg1 <= arg2

gt 		大于	操作符	arg1 > arg2

ge 		大于等于 	操作符: arg1 >= arg2

Examples

Funcs

package main

import (
	"log"
	"os"
	"strings"
	"text/template"
)

func main() {
	// 首先创建一个函数字典用于注册函数
	funcMap := template.FuncMap{
		// 注册函数title, strings.Title会将单词首字母大写
		"title": strings.Title,
	}

	// A simple template definition to test our function.
	// 打印输出文本
	// - 原样
	// - 执行title后的
	// - 执行title和printf
	// - 执行printf和title
	const templateText = `
Input: {{printf "%q" .}}
Output 0: {{title .}}
Output 1: {{title . | printf "%q"}}
Output 2: {{printf "%q" . | title}}
`

	// 创建模板, 添加模板函数,添加解析模板文本.
	tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)
	if err != nil {
		log.Fatalf("parsing: %s", err)
	}

	// 运行模板,出入数据参数
	err = tmpl.Execute(os.Stdout, "the go programming language")
	if err != nil {
		log.Fatalf("execution: %s", err)
	}

}

运行结果:

➜  template git:(master) ✗ go run text_f2.go 

Input: "the go programming language"
Output 0: The Go Programming Language
Output 1: "The Go Programming Language"
Output 2: "The Go Programming Language"

block

package main

import (
	"log"
	"os"
	"strings"
	"text/template"
)

func main() {
	const (
		master  = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}`
		overlay = `{{define "list"}} {{join . ", "}}{{end}} `
	)
	var (
		funcs     = template.FuncMap{"join": strings.Join}
		guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"}
	)
	masterTmpl, err := template.New("master").Funcs(funcs).Parse(master)
	if err != nil {
		log.Fatal(err)
	}
	overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay)
	if err != nil {
		log.Fatal(err)
	}
	if err := masterTmpl.Execute(os.Stdout, guardians); err != nil {
		log.Fatal(err)
	}
	if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil {
		log.Fatal(err)
	}
}

更多

关于template的嵌套执行,因为开发中很少用到,不做讲解,可阅读官网:http://docs.studygolang.com/pkg/text/template/#Nested template definitions


  1. http://docscn.studygolang.com/pkg/html/template/ ↩︎

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值