概述
text/template實現基於數據的文本化輸出。功能和jsp、blade.php(laravel)一樣,用於動態生成文件,只不過golang用於生產HTML的模塊為html/template1
運行過程
將template模板應用於結構化的數據,使用注解語法引用數據結構中的元素(struct中的feild或map中的key)並顯示它們的值。template在執行過程中遍歷數據結構並且設置當前光標(英文句號“.”標識)標識當前位置的元素(值)
一旦解析,模板可以安全地並行執行,但是如果並行執行共享Writer,則輸出可以是交錯的。
要求
template的文本必須為UTF-8編碼。注解語法必須由“{{”和“}}”分隔,不在“{{”和“}}”的文本原樣輸出。一般來說注解語法不用另起一行,可以和非注解文本同行,不過如果是動態注釋的話,注解語法還是建議另起一行。
遍歷struct
1 type Inventory struct { 2 Material string 3 Count uint 4 } 5 sweaters := Inventory{"wool", 17} 6 tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}") 7 if err != nil { panic(err) } 8 err = tmpl.Execute(os.Stdout, sweaters) 9 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
雖然所有在“{{}}”控制注解之外的文本會默認一分不差地復制到輸出中,但是如果“{{”緊接着跟隨“—”和“ ”的話,那么“{{”之前的文本中的空白(空格、換行符、回車符、制表符)會被移除。對應的,“ -}}”表示移除之后文本中的空白。
例如上面例子,稍作修改:
1 package main 2 3 import ( 4 "os" 5 "text/template" 6 ) 7 8 type Inventory struct { 9 Material string 10 Count uint 11 } 12 13 func main(){ 14 sweaters := Inventory{"wool", 17} 15 tmpl, err := template.New("test").Parse("{{.Count -}} items are made of {{- .Material}}") 16 if err != nil { panic(err) } 17 err = tmpl.Execute(os.Stdout, sweaters) 18 if err != nil { panic(err) } 19 }
執行結果:
➜ template git:(master) ✗ go run text_template.go
17items are made ofwool%
Actions
以下pipeline是對數據的假設
- 注釋
{{/* 注釋 */}}
{{- /* 去掉前后空白 */ -}}
//action的注釋不會被輸出,且必須在“{{}}”內,由“/*”和“*/”包含
2. 文本化輸出
{{pipeline}}
//pipeline值的文本化表示被復制到輸出
3. 判斷結構
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}}
4. 循環結構
{{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。
5. 模板嵌套
{{template "name"}}
執行指定模板name, 無任何數據傳入
{{template "name" pipeline}}
執行指定模板name, pipeline數據傳入
{{block "name" pipeline}} T1 {{end}}
定義模板name並執行模板,傳入數據pipeline
6. with
{{with pipeline}} T1 {{end}}
如果pipeline不為空,那么執行T1, 並將光標“.” 設置為pipeline
{{with pipeline}} T1 {{else}} T0 {{end}}
如果pipeline不為空,那么執行T1, 並將光標“.” 設置為pipeline;否則,執行T0, 光標“.”不受影響
7. 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
8. 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 創建變量和使用管道“|”
9. 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
1 package main 2 3 import ( 4 "log" 5 "os" 6 "strings" 7 "text/template" 8 ) 9 10 func main() { 11 // 首先創建一個函數字典用於注冊函數 12 funcMap := template.FuncMap{ 13 // 注冊函數title, strings.Title會將單詞首字母大寫 14 "title": strings.Title, 15 } 16 17 // A simple template definition to test our function. 18 // 打印輸出文本 19 // - 原樣 20 // - 執行title后的 21 // - 執行title和printf 22 // - 執行printf和title 23 const templateText = ` 24 Input: {{printf "%q" .}} 25 Output 0: {{title .}} 26 Output 1: {{title . | printf "%q"}} 27 Output 2: {{printf "%q" . | title}} 28 ` 29 30 // 創建模板, 添加模板函數,添加解析模板文本. 31 tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText) 32 if err != nil { 33 log.Fatalf("parsing: %s", err) 34 } 35 36 // 運行模板,出入數據參數 37 err = tmpl.Execute(os.Stdout, "the go programming language") 38 if err != nil { 39 log.Fatalf("execution: %s", err) 40 } 41 42 }
運行結果:
➜ 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"
1 package main 2 3 import ( 4 "log" 5 "os" 6 "strings" 7 "text/template" 8 ) 9 10 func main() { 11 const ( 12 master = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}` 13 overlay = `{{define "list"}} {{join . ", "}}{{end}} ` 14 ) 15 var ( 16 funcs = template.FuncMap{"join": strings.Join} 17 guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"} 18 ) 19 masterTmpl, err := template.New("master").Funcs(funcs).Parse(master) 20 if err != nil { 21 log.Fatal(err) 22 } 23 overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay) 24 if err != nil { 25 log.Fatal(err) 26 } 27 if err := masterTmpl.Execute(os.Stdout, guardians); err != nil { 28 log.Fatal(err) 29 } 30 if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil { 31 log.Fatal(err) 32 } 33 }
原文鏈接:https://blog.csdn.net/u012386544/article/details/84535586
