Go
golang
Web
go-web-examples

Go Web Examplesの和訳(Templates)

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>