[Go言語] templateパッケージでtwigとかのextends的なあれをやるにはどうしようか

September 29, 2013

この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。

やりたいこと

twigでいくと以下のようなやつ。 でも、デフォルトがあってそれを上書きするとかいう機能は別にいらない。 共通部分を使い回せればそれでいい。

参考:http://twig.sensiolabs.org/doc/tags/extends.html

<!DOCTYPE html>
<html>
    <head>
        {% block head %}
            <link rel="stylesheet" href="style.css" />
            <title>{% block title %}{% endblock %} - My Webpage</title>
        {% endblock %}
    </head>
    <body>
        <div id="content">{% block content %}{% endblock %}</div>
        <div id="footer">
            {% block footer %}
                &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
            {% endblock %}
        </div>
    </body>
</html>
{% extends "base.html" %}

{% block title %}Index{% endblock %}
{% block head %}
    {{ parent() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
        Welcome on my awesome homepage.
    </p>
{% endblock %}

やってみた

とりあえず、PlayGroundでやってみた。

http://play.golang.org/p/YQd6ChZFqd

package main

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

var layoutStr = `{{define "layout"}}header
{{template "content"}}
footer{{end}}`

var hogeStr = `{{define "content"}}hoge{{end}}`

var piyoStr = `{{define "content"}}piyo{{end}}`

func main() {
	hoge := template.Must(template.New("hoge").Parse(hogeStr))
	hoge.Parse(layoutStr)
	hoge.ExecuteTemplate(os.Stdout, "layout", nil)

	fmt.Println()

	piyo := template.Must(template.New("piyo").Parse(piyoStr))
	piyo.Parse(layoutStr)
	piyo.ExecuteTemplate(os.Stdout, "layout", nil)

}

もっとちゃんとやってみた

https://github.com/golang-samples/template/tree/master/extends

baseを作る

まずは、baseとなるhtmlを作る。 テンプレートの名前は、baseとしておく。 templatecontentという別のテンプレートを読み込んでいる。

{{define "base"}}
<!DOCTYPE html>
<html>
    <body>

      <header>
        <h1>Title of {{.}}</h1>
        <nav>
          <ul>
            <li><a href="hoge">Hoge</a></li>
            <li><a href="piyo">Piyo</a></li>
          </ul>
        </nav>
      </header>

      <article id="content">
        {{template "content" .}}
      </article>

      <footer>
        &copy; Copyright 2013 by golang-samples.
      </footer>
    </body>
</html>
{{end}}

コンテンツを作る

続いて、コンテンツとなるhtmlを作る。 base.htmlに埋め込まれるので、テンプレートの名前は2つともcontentにしておく。

{{define "content"}}
<h1>Hoge</h1>
<p>
  I'm Hoge.
</p>
{{end}}
{{define "content"}}
<h1>Piyo</h1>
<p>
  I'm Piyo.
</p>
{{end}}

Goから読み込む

以下のように、別々のテンプレートとしてパースすることで、contentという名前が被ってもできる。もちろん、ParseGlobとかで一気にパースするとダメ。

ベースで指定した部分を上書きするtwigのextendsの方が自由度高いが、まぁコレくらいできたら別にいいや。

package main

import (
	"html/template"
	"net/http"
)

var hogeTmpl = template.Must(template.New("hoge").ParseFiles("base.html", "hoge.html"))

func hogeHandler(w http.ResponseWriter, r *http.Request) {
	hogeTmpl.ExecuteTemplate(w, "base", "Hoge")
}

var piyoTmpl = template.Must(template.New("piyo").ParseFiles("base.html", "piyo.html"))

func piyoHandler(w http.ResponseWriter, r *http.Request) {
	piyoTmpl.ExecuteTemplate(w, "base", "Piyo")
}

func main() {
	// hoge
	http.HandleFunc("/", hogeHandler)
	http.HandleFunc("/hoge", hogeHandler)

	// piyo
	http.HandleFunc("/piyo", piyoHandler)

	http.ListenAndServe(":8080", nil)
}