March 19, 2012

1511 letters 4 mins read

Go言語:templateパッケージでHTML等テキストファイルを読み込む(基礎編)

templateパッケージでHTML等の任意のテキストファイルを読み込み、出力する方法を説明する。
なお、APIバージョンGo1で説明する。
バージョン3ではパッケージ名、関数名が異なるので注意。

概要

templateパッケージでは、任意のテキストファイルを読み込み、テキストファイルに埋め込まれたプレースホルダに文字列を変換して出力する。例えば、以下のような機能を利用できる。

  • ブラウザからのgetリクエストに対して外部HTMLファイルを読み込み、任意のデータをHTMLに埋め込んでレスポンスとして返す。
  • メールの本文テンプレートとして作成したテキストファイルを読み込み、任意のデータを本文に埋め込んでメールを送信する。

単にhtmlファイルを読み込んで出力するだけのサンプル

package main

import (
    "os"
    "fmt"
    "text/template"
)

func main() {
	var t = template.Must(template.ParseFiles("plainSample.html")) // 外部テンプレートファイルの読み込み
    
	if err := t.Execute(os.Stdout, nil); err != nil { // テンプレート出力
        fmt.Println(err.Error())
    }
}

plainSample.html

<html>
    <head>
        <title>Sample Html</title>
    </head>
    <body>
        <h1>Htmlサンプル</h1>
        サンプルテキスト
    </body>
</html>

出力結果

<html>
    <head>
        <title>Sample Html</title>
    </head>
    <body>
        <h1>Htmlサンプル</h1>
        サンプルテキスト
    </body>
</html>

プレースホルダを使用した場合のサンプル

package templatesample

import (
    "fmt"
    "net/http"
    "text/template"
)

type Member struct {
    Name string
    Message string
}

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
    member := Member{"inatus", "はじめまして。<br>よろしくお願いいたします。"}
    var t = template.Must(template.ParseFiles("placeholderSample.html")) // 外部テンプレートファイルの読み込み
    
	if err := t.Execute(w, member); err != nil { // テンプレート出力
        fmt.Println(err.Error())
    }
}

placeholderSample.html

<html>
    <head>
        <title>Sample Html</title>
    </head>
    <body>
        <h1>Htmlサンプル</h1>
        <h3>{{.Name}}</h3>
        {{.Message}}
    </body>
</html>

ブラウザ表示結果

出力をstring型のオブジェクトに格納するサンプル

package main

import (
    "fmt"
    "bytes"
    "text/template"
)

type Member struct {
    Name string
    Message string
}

func main() {
    member := Member{"inatus", "はじめまして。<br>よろしくお願いいたします。"}
    var body bytes.Buffer
    var t = template.Must(template.ParseFiles("placeholderSample.html")) // 外部テンプレートファイルの読み込み
    
	if err := t.Execute(&body, member); err != nil { // テンプレート出力
        fmt.Println(err.Error())
    }

    var str string = body.String()
}

解説

パッケージ

下記の2種がある。

  • text/template: 汎用テンプレート用のパッケージ。
  • html/template: プレースホルダに変換対象の文字列のhtmlタグをエスケープする。サニタイジングに有効。

インポートするパッケージをhtml/templateに変更して上記の「プレースホルダを使用した場合のサンプル」を実行した結果は以下の通り。

内部的には<<>>といったように文字列変換される。

テンプレートの読み込み

var t = template.Must(template.ParseFiles("placeholderSample.html"))

template.ParseFiles関数の引数で渡すパスにあるファイルを読み込む。
パスではなくstringをそのまま引数に渡すこともできる。

var t = template.Must(template.New("html").Parse("<html><body>サンプル</body></html>"))

プレースホルダ変換文字列の指定と出力

if err := t.Execute(w, member); err != nil { // テンプレート出力
    fmt.Println(err.Error())
}

上記のテンプレート読み込みの出力変数に対しExecute関数を実行する。
1つ目の引数には出力先のio.Writerインタフェイスを指定する。io.Writerインタフェイスには例えば下記のようなものがある。

  • http.ResponseWriter: httpレスポンスへの出力
  • os.Stdout: 標準出力
  • bytes.Buffer: 変数への出力

2つ目の引数にはプレースホルダへの変換対象となる文字列を含んだ変数(通常は構造体)を指定する。読み込んだテンプレートのプレースホルダ名({{.Variable}})は必ず構造体のメンバ名として存在しなければならない。

応用編では使用できるプレースホルダのバリエーションを解説する。