Go言語:templateパッケージでHTML等テキストファイルを読み込む(応用編1)
templateパッケージでHTML等の任意のテキストファイルを読み込み、出力する方法を説明する。 応用編ではテンプレート内に埋め込む「アクション」について解説する。 なお、APIバージョンGo1で説明する。 バージョン3ではパッケージ名、関数名が異なるので注意。
概要
templateパッケージでは、任意のテキストを読み込み、テキストに埋め込まれたタグに対してデータの評価や制御(アクションという)をおこなって出力する。いくつかのアクションの指定により、以下のようなことができる。
- テンプレートに渡された引数や構造体のフィールドを出力する。
- テンプレートに渡されたbool値を評価し、出力を制御する。
- テンプレートに渡された配列、Slice、Mapのデータを繰り返し出力する。
例
配列の要素をすべて表示するサンプル
package main
import (
"fmt"
"os"
"text/template"
)
const templateString string = `テンプレートの始め
{{range .}}
繰り返し処理 {{.}}
{{end}}
テンプレートの終わり
`
func main() {
var stringArray []string = []string{"Hello", "World", "!!!!"}
var t = template.Must(template.New("html").Parse(templateString))
if err := t.Execute(os.Stdout, stringArray); err != nil { // 配列を渡す
fmt.Println(err.Error())
}
}
出力結果
テンプレートの始め
繰り返し処理 Hello
繰り返し処理 World
繰り返し処理 !!!!
テンプレートの終わり
構造体、Mapの要素の表示、if文による条件分岐を用いたサンプル
package main
import (
"fmt"
"os"
"text/template"
)
type Struct struct {
SampleString string
SampleMap map[string]MapValue
SampleBool bool
}
type MapValue struct {
IntValue int
StringValue string
}
const templateString string = `テンプレートの始め
{{with .}}
Structが空でなければこの先を出力する
{{.SampleString}}:フィールドの値を出力
{{range .SampleMap}}
Mapの繰り返し処理 {{.IntValue}}: {{.StringValue}}
{{end}}
{{if .SampleBool}}
bool変数がtrueならば出力
{{else}}
bool変数がfalseならば出力
{{end}}
{{end}}
テンプレートの終わり
`
func main() {
values := Struct{"サンプルテキスト", make(map[string]MapValue), false}
values.SampleMap["first"] = MapValue{1, "Hello"}
values.SampleMap["second"] = MapValue{2, "World"}
values.SampleMap["third"] = MapValue{3, "!!!!"}
var t = template.Must(template.New("text").Parse(templateString))
if err := t.Execute(os.Stdout, values); err != nil { // 構造体を渡す
fmt.Println(err.Error())
}
}
出力結果
テンプレートの始め
Structが空でなければこの先を出力する
サンプルテキスト:フィールドの値を出力
Mapの繰り返し処理 1: Hello
Mapの繰り返し処理 2: World
Mapの繰り返し処理 3: !!!!
bool変数がfalseならば出力
テンプレートの終わり
解説
アクションタグの種類
{{.}}
テンプレートに渡された引数を出力する。
{{.Member}}
テンプレートに渡された引数が構造体の場合、Member
フィールドの値を出力する。
{{if .}} 分岐1 {{else}} 分岐2 {{end}}
テンプレートに渡された引数のbool値がtrueの場合「分岐1」が出力され、falseの場合「分岐2」が出力される。{{else}}
は省略できる。
{{range .}} {{.}} {{else}} なし {{end}}
テンプレートに渡された引数が配列、Slice、Mapの場合、lengthが1以上の場合はすべての要素を表示し({{.}}
を要素数分繰り返し)、lengthが0の場合には「なし」が表示される。{{else}}
は省略できる。
{{with .}} 分岐1 {{else}} 分岐2 {{end}}
テンプレートに渡された引数の値が空でない場合「分岐1」が出力され、空の場合「分岐2」が出力される。{{else}}
は省略できる。
応用
テンプレートを実際のWebアプリケーションに用いる例を紹介する。 サンプルとしてLegacy-BBSを参照してもらいたい。 このサンプルは、下記の2つの部分に分かれている。
- メッセージを投稿するためのフォーム部分
投稿時に名前やメッセージが空白でないかのバリデーションを行い、エラーメッセージを表示する。
バリデーションの結果を
{{if}}
で判定し、エラーの表示をおこなう。 - 投稿されたメッセージを表示する部分
データストアに格納されている複数のメッセージを表示する。
メッセージは構造体
Entry_view
の配列に格納し、{{range}}
により表示をおこなう。
構造体とテンプレートのサンプルは下記の通り。 なお、この例にはこれらの構造体のデータを取得・出力するロジックは省略している。 ロジックについてはまた別の機会に説明する。
type View struct {
Entries []Entry_view
Errors Validation
}
type Entry_view struct {
Name string
Email string
Title string
Message string
Date string
}
type Validation struct {
NameError bool
MessageError bool
}
<html>
<body>
<p>Legacy BBS Sample</p>
{{/* メッセージを投稿するためのフォーム部分 */}}
<form method="POST" action="">
{{with .Errors}}
Submitter
<input type="text" name="name" /><br />
{{if .NameError}}<font color="red">Enter a submitter</font><br />{{end}}
Mail
<input type="text" name="email" /><br />
Title
<input type="text" name="title" /><br />
Message
<textarea name="message"></textarea><br />
{{if .MessageError}}<font color="red">Enter a message</font><br />{{end}}
<input type="submit" name="submit" value="Submit" />
{{end}}
</form>
{{/* 投稿されたメッセージを表示する部分 */}}
{{range .Entries}}
<hr />
<p>
{{.Title}} Submitter:
{{if .Email}}<a href="mailto:{{.Email}}">{{.Name}}</a>
{{else}}{{.Name}}
{{end}}
Date: {{.Date}}
</p>
<p>{{.Message}}</p>
{{end}}
</body>
</html>
応用編2ではアクションタグに使用できる関数や変数を説明する。