golangのテンプレートエンジン(html/template)ではデフォルトで組み込み関数が用意されていますが, 物足りない場合は自作する事になります.
考え方
基本は以下です.
- template.FuncMapを作る(関数名と関数のmap)
- このmapをテンプレートのFuncs関数に渡して登録する
FuncMapに登録する関数は以下の規約があるようです.
- 引数はいくつでもOK
- 戻り値は1つだけ
- ただし2つ目がerrorなら戻り値2つもOK
2つ目の戻り値errorがnilでなければ処理は中断し, Execute関数はtemplate.ExecErrorを返します.
サンプルコード
実用的とは言えない例ですが.
package main import ( "fmt" "html/template" "net/http" "time" ) // 年-月-日にフォーマット func formatDate(t time.Time) string { layout := "2006-01-02" return t.Format(layout) } // 引数の文字列を頭文字を大文字にして連結して返す. // 合計文字数が15バイトを超えたらエラーにする func CatAndUpper(args ...string) (string, error) { ret := "" for _, s := range args { ret += s } if len(ret) >= 15 { return "", fmt.Errorf("too long string") } return ret, nil } // 頭に$を付けるだけ func formatDollar(c int) string { return fmt.Sprintf("$%d", c) } func testHandler(w http.ResponseWriter, r *http.Request) { // カスタム関数を登録 fm := template.FuncMap{ "fdate": formatDate, "fdollar": formatDollar, "cat": CatAndUpper, } t := template.New("tmpl.html").Funcs(fm) t, _ = t.ParseFiles("tmpl.html") // 流し込む適当なデータ data := &struct { Date time.Time Dollar int }{} data.Date = time.Now() data.Dollar = 100 // テンプレート実行 fmt.Println(t.Execute(w, data)) } func main() { http.HandleFunc("/", testHandler) http.ListenAndServe(":8080", nil) }
サンプルテンプレート
<html> <head> </head> <body> <div>日付: {{fdate .Date}}</div> <div>ドル: {{fdollar .Dollar}}</div> <div>つなげる: {{cat "string" "string2"}}</div> <div>長いのつなげる: {{cat "string" "string2" "string3"}}</div> </body> </html>
生成されるHTML
途中でエラーを返しているので途中まで生成して止まっています.
<html> <head> </head> <body> <div>日付: 2017-09-19</div> <div>ドル: $100</div> <div>つなげる: stringstring2</div> <div>長いのつなげる:
コンソール
テンプレート内でエラーを起こしたのでExecuteメソッドのエラーが帰ってきています.
今回はfmt.Printlnで標準出力へ出してみました.
$ ./sample.exe template: tmpl.html:8:32: executing "tmpl.html" at <cat "string" "string...>: error calling cat: too long string