Go勉強会 Webアプリケーション編 #2で使おうと思っているGo Web Examplesの和訳です。ほぼGoogle翻訳ですが、リンク等も整理された状態であると便利だと思い作りました。次回(Requests & Forms)
はじめに
Goのhtml/templateパッケージはHTMLテンプレート用の豊富なテンプレート言語を提供します。主にWebアプリケーションで使用され、クライアントのブラウザで構造化データを表示します。Goのテンプレート言語の大きな利点の1つは、データを自動でエスケープすることです。GoはHTMLテンプレートを解析し、すべての入力をエスケープしてからブラウザに表示するので、XSS攻撃については心配する必要はありません。
最初のテンプレート
Goのテンプレートの書き方は非常にシンプルです。この例では、HTMLの順序付けられていないリスト(ul)として記述されたTODOリストを示しています。レンダリングテンプレートの場合、渡されるデータはあらゆる種類のGoのデータ構造になります。これは単純な文字列または数値でもよく、下の例のようにネストされたデータ構造でも可能です。テンプレート内でデータにアクセスするには、変数の先頭を {{.}}
にしてアクセスします。中括弧内のドットはパイプラインとデータのルート要素と呼ばれます。
data := TodoPageData{
PageTitle: "My TODO list",
Todos: []Todo{
{Title: "Task 1", Done: false},
{Title: "Task 2", Done: true},
{Title: "Task 3", Done: true},
},
}
<h1>{{.PageTitle}}<h1>
<ul>
{{range .Todos}}
{{if .Done}}
<li class="done">{{.Title}}</li>
{{else}}
<li>{{.Title}}</li>
{{end}}
{{end}}
</ul>
制御構造
テンプレート言語には、HTMLをレンダリングするための豊富なコントロール構造が含まれています。ここでは、最も一般的に使用されるものの概要を紹介します。すべての可能な構造の詳細なリストを入手するにはtext/templateを参照してください。
制御構造 | 定義 |
---|---|
{{/* a comment */}} | コメントを定義します |
{{.}} | ルート要素をレンダリングします |
{{.Title}} | ネストされた要素の"Title"フィールドをレンダリングします |
{{if .Done}} {{else}} {{end}} | if-statementを定義します |
{{range .Todos}} {{.}} {{end}} | すべての"Todos"をループし{{.}} を利用してそれらをレンダリングします |
{{block "content" .}} {{end}} | "content"という名前のブロックを定義します |
ファイルからのテンプレート解析
テンプレートは、文字列やディスク上のファイルから解析することができます。通常の場合、テンプレートはディスクからのpares(※parseのtypo?)です。この例では、その方法を示しています。この例では、Goプログラムと同じディレクトリにテンプレートファイルlayout.html
があります。
tmpl, err := template.ParseFiles("layout.html")
// or
tmpl := template.Must(template.ParseFiles("layout.html"))
Request Handler 内でテンプレートを実行する
テンプレートがディスクから解析されると、そのテンプレートはリクエストハンドラ内で使用できる状態になります。
Execute
関数はテンプレートを書き込むためのio.Writer
とテンプレートにデータを渡すためのinterface {}
を受け入れます。
関数がhttp.ResponseWriter
で呼び出されると、Content-Typeヘッダには自動でContent-Type: text/html; charset=utf-8
が設定されます。
func(w http.ResponseWriter, r *http.Request) {
tmpl.Execute(w, "data goes here")
}
コピペ用コード
これは、この例で学んだことを試すために使用できる完全なコードです。
package main
import (
"html/template"
"net/http"
)
type Todo struct {
Title string
Done bool
}
type TodoPageData struct {
PageTitle string
Todos []Todo
}
func main() {
tmpl := template.Must(template.ParseFiles("layout.html"))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
data := TodoPageData{
PageTitle: "My TODO list",
Todos: []Todo{
{Title: "Task 1", Done: false},
{Title: "Task 2", Done: true},
{Title: "Task 3", Done: true},
},
}
tmpl.Execute(w, data)
})
http.ListenAndServe(":80", nil)
}
<h1>{{.PageTitle}}<h1>
<ul>
{{range .Todos}}
{{if .Done}}
<li class="done">{{.Title}}</li>
{{else}}
<li>{{.Title}}</li>
{{end}}
{{end}}
</ul>