2017年6月27日 星期二

Golang : Template 操作

golang template 渲染執行變數與操作方法筆記。

text/template, html/template 使用

最主要 text/template 是核心的模板功能,只輸出傳文字的功能,而 html/template 是基於 text/template 的功能之上開發的模組, 像是 html/template 會自動在輸出時先把文字載入脫曳字元,也包含許多預設的方法。

詳情可以參考: https://golang.org/pkg/html/template/

結構

template 使用上,是先做 ParseFiles, ParseGlob 之類的行為,來讀取檔案,再透過 Execute, ExecuteTemplate 之類的方法來把模板回傳到 response 。

基本的渲染程式如下:
func main() {

        // select the file want to parse.
 tpl, err := template.ParseFiles("index.html")

        //execute printout to stdout or response.
 err := tpl.Execute(os.Stdout, nil)
 if err != nil {
  panic(err)
 }
}

模板路徑

以下介紹兩種分別為 ParseFiles 和 ParseGlob 的讀取模板檔案的方式。
用 ParseFiles 讀取模板, 方法是這樣寫的:
tpl, err := template.ParseFiles("index.html", "./widget/widget-1.html", "widget-2.html") //(...)
其中 ParseFiles 的模組參數,是寫 ... ,所以你可以丟入所有模板的路徑,不過也只能丟固定檔案名稱。

而 ParseGlob 是可以用 Patterns 的模式,來抓到所有符合條件的檔案,它是這樣寫的:
tpl, err := template.ParseGlob("./*.html")
而這樣寫之後只要該目錄符合 .html 的副檔名,就會被讀進去。

Must

template.Must 可以幫你檢查模板使用是否有錯誤,然後再回傳單一一個 template 的類型,官方的模組是這樣寫的:
func Must(t *Template, err error) *Template {
   if err != nil {
    panic(err)
   }
   return t
  }
所以執行後,不需要再用 err 接收。

實際用法是這樣:
tpl := template.Must(template.New("").ParseGlob("./*.html"))

Execute 與提取變數到 Template

將變數丟到 Template,需要將變數作為參數放在 Execute 類的方法中,變數可以接受任何的值, struct, slice, value 之類,但是只能加一個參數進去。

程式寫法如下:
//如果你是使用 ParseGlob 來解析檔案,記得要在 ExecuteTemplate 的第二個參數告訴模組要把哪個檔案作為主要渲染的模板。
err := tpl.ExecuteTemplate(os.Stdout, "index.html", data)

//如果是 ParseFile ,用 Execute 就可以了
//err := tpl.Execute(os.Stdout, data)
if err != nil {
 panic(err)
}

其中的這個 data 參數,就是要放入 template 的值,這裡以 string 為例:
var data []string = []string{"1", "2", "3", "Hello World"}

丟入方法函數到 template

要在 template 中使用自己設定的方法,需要建立一個 struct ,然後在 ParseFiles 類的操作之前,加入這個 struct。

寫法:
var fc = template.FuncMap{
 "conv": convetor,  //加入自己的方法
}

func convetor(data string) string {
 return fmt.Sprintln("give some value: ", data)
}

var tpl *template.Template

func init() {
        //重點在於 Funcs 這個方法,參數是加入含有 FuncMap 結構的 struct,這麼一來就可以在模板中使用,且必須在 Parse 之前就加入 Func。
 tpl = template.Must(template.New("").Funcs(fc).ParseGlob("./*.html"))

        //單純用 ParseFiles 的方法
        //tpl = template.Must(template.New("index.html").Funcs(fc).ParseFiles("index.html"))
}

於 Template 的操作,在下一節會提到。

Template 常用方法、變數使用

Template 可以自訂任何檔案,只要輸入檔案進去給 ParseFiles 或可以被 ParseGlob 讀取就可以了。

. 點

在 Template 中,要顯示 Execute 的變數,要使用 {{ . }} ,這個點只會是一次性的,因為 Execute 的方法無法讀取多個變數,所以 {{ . }}} 將代表剛才寫的 data 。
<p>{{.}}</p>

而如果傳入的 data 是一個 struct , 可能就會這樣寫:
<p>{{.FirstName}}</p>

自訂變數

Template 可以自訂變數,如果你覺得依靠 . 有點不好讀取,可以事先定義:
<p>{{ $data := .}}, read data: {{ $data.FirstName }}</p>

迴圈

由於可能傳入的參數是 Slice 或是 map ,可以透過以下方法存取:
//讀取 slice (array)
{{ range . }} //. 也可以寫 $data
    //這個 . 已經被換成迴圈的 . ,在這個區域內, . 不是 data 了,而是被迭代的內容。
 <p>{{.}}</p>
{{end}}

//讀取 map 的方式
{{ range $key,$v := $data }}
    <p>{{$key}} - {{ $v }}</p>
{{end}}

 判斷 / 比較

在 Template 使用判斷,是使用以下方法:
// if lt(小於) 第一個參數, 第二個, ....
{{if lt 1 2 }}
    1 < 2
{{ end }}

// if eq(等於) 第一個參數,第二個, ...
{{ if eq 1 1}}
    1 == 1
{{ end }}

// if gt(大於) 第一個參數,第二個, ...
{{ if gt 2 1 }}
    2 > 1
{{ end }}

// if (布林)
{{ if true }}

{{ end }}

套用方法/函數

剛才在 if 中使用的 gt, eq, lt 其實就是 使用方法/函數的方式,在上一節所寫到的 conv 函式,在這裡的使用方法是:
{{ conv . }}

//或

{{ conv "hello world" }}

//如果多個參數的情況下

{{ conv "1" "2"}}

pipeline 多重套用函數

如果使用多重的方法,可以這樣寫:
{{ . | conv | toUpperCase | toLowerCase }}

分離式模板

要做到分離式模板, ParseFiles 和 ParseGlob 最好有不同的 html ,而且都要讀入,分離式模板的方法會在 Execute 就被執行,所以不用擔心 Execute 讀取不到要載入的分離式模板。

widget.html:
//需要事先定義好 define
{{ define "splite" }}
 <p>Hello world, this template is from splite.html, and this string is from {{.}}</p>

 //{{ . }} 是接收來自呼叫者的參數
{{end}}

index.html:
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Demo page</title>
    </head>
    <body>

     //第一個參數是輸入 define 的名稱,然後丟入需要的參數
        {{ template "splite" " =>index.html"}}

    </body>
</html>

如此一來 Template 就會被組合在一起。

Reference:
https://golang.org/pkg/html/template/
https://golang.org/src/text/template/helper.go
https://astaxie.gitbooks.io/build-web-application-with-golang/en/07.4.html

沒有留言:

張貼留言

© Mac Taylor, 歡迎自由轉貼。
Background Email Pattern by Toby Elliott
Since 2014