標準ライブラリを使用してGoにネストされたテンプレートを作成することは可能ですか?


87

JinjaがPythonランタイムに持っているようなネストされたテンプレートを取得するにはどうすればよいですか。TBCが意味するのは、Jinja / django-templatesのように、基本テンプレートのブロックにファイリングするだけで、一連のテンプレートを基本テンプレートから継承させる方法です。html/template標準ライブラリだけで使用できますか?

それが不可能な場合、私の選択肢は何ですか。口ひげはオプションのhtml/templateようですが、状況依存のエスケープなどの素晴らしい微妙な機能を見逃しているでしょうか?他にどのような選択肢がありますか?

(環境:Google App Engin、Goランタイムv1、開発-Mac OSx lion)

読んでくれてありがとう。

回答:


132

はい、可能です。Ahtml.Templateは実際にはテンプレートファイルのセットです。このセットで定義されたブロックを実行すると、このセットで定義された他のすべてのブロックにアクセスできます。

このようなテンプレートセットのマップを自分で作成する場合、基本的にJinja / Djangoが提供するのと同じ柔軟性があります。唯一の違いは、html / templateパッケージはファイルシステムに直接アクセスできないため、テンプレートを自分で解析して作成する必要があることです。

どちらも「base.html」から継承する2つの異なるページ(「index.html」と「other.html」)を持つ次の例について考えてみます。

// Content of base.html:
{{define "base"}}<html>
  <head>{{template "head" .}}</head>
  <body>{{template "body" .}}</body>
</html>{{end}}

// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}

// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}

そして、次のテンプレートセットのマップ:

tmpl := make(map[string]*template.Template)
tmpl["index.html"] = template.Must(template.ParseFiles("index.html", "base.html"))
tmpl["other.html"] = template.Must(template.ParseFiles("other.html", "base.html"))

これで、を呼び出すことで「index.html」ページをレンダリングできます。

tmpl["index.html"].Execute("base", data)

呼び出して「other.html」ページをレンダリングできます

tmpl["other.html"].Execute("base", data)

いくつかのトリック(たとえば、テンプレートファイルの一貫した命名規則)を使用すると、tmplマップを自動的に生成することも可能です。


3
たとえば、「頭」のデフォルトデータを持つことは可能ですか?
gregghz 2012年

18
ここに、実際のテンプレートをレンダリングするために呼び出す必要があることを追加しますtmpl["index.html"].ExecuteTemplate(w, "base", data)
hermansc 2013年

base.htmlは解析され、2回保存されます。golang.org/pkg/text/template/#example_Template_share
Maarten O.

3
ネストされたテンプレートにデータを渡すときに問題が発生します。からのデータ{{ .SomeData }}は内部テンプレートに表示されません。アウターワークス。
0xAffe 2016

かどうかは重要template.ParseFiles("index.html", "base.html")ですかtemplate.ParseFiles("base.html", "index.html")
shackra 2017

10

ベーステンプレートを実行するときは、子テンプレートに値を渡す必要があることに注意してください。ここでは、単に「。」を渡すだけなので、すべてが渡されます。

テンプレート1は{{。}}を表示します

{{define "base"}}
<html>
        <div class="container">
            {{.}}
            {{template "content" .}}
        </div>
    </body>
</html>
{{end}}

テンプレート2は、親に渡された{{.domains}}を表示します。

{{define "content"}}
{{.domains}}
{{end}}

{{template "content"。}}の代わりに{{template "content"。}}を使用した場合、コンテンツテンプレートから.domainsにアクセスできないことに注意してください。

DomainsData := make(map[string]interface{})
    DomainsData["domains"] = domains.Domains
    if err := groupsTemplate.ExecuteTemplate(w, "base", DomainsData); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }

5
モデルを引き継ぐことは私が固執した詳細です。;)ありがとう
Patrick

1
私も-理解するのに少し時間がかかりました:)
ロバートキング

1
何!{{template}}プレースホルダーの最後にある小さな小さな点にそれほど多くの意味があったとは信じられません。なぜそれがチュートリアルや公式のGoドキュメントのどこにも言及されていないのですか?私はびっくりしました...しかし、あなたの答えを見つけてとても幸せです!どうもありがとうございました。これで、いくつかのレベルのネストを備えた私のテンプレートが美しく機能します。
Gwyneth Llewelyn 2017年

まさに、私が理解しようとしていたのと同じことです!
devforfu

5

他のテンプレートパッケージを使用してきましたが、現在は主に標準のhtml / templateパッケージを使用していますが、それが提供するシンプルさやその他の優れた点に感謝しないのは素朴だったと思います。私は以下の変更を加えて、受け入れられた回答に非常に類似したアプローチを使用します

レイアウトを追加のbaseテンプレートでラップする必要はありません。解析されたファイルごとにテンプレートブロックが作成されるため、この場合は冗長です。新しいバージョンのgoで提供されているブロックアクションを使用することもできます。子テンプレートで提供しない場合のデフォルトのブロックコンテンツ

// base.html
<head>{{block "head" .}} Default Title {{end}}</head>
<body>{{block "body" .}} default body {{end}}</body>

ページテンプレートはと同じにすることができます

// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}

// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}

テンプレートを実行するには、そのように呼び出す必要があります

tmpl["index.html"].ExecuteTemplate(os.Stdout, "base.html", data)

4

Djangoと同様に、テンプレート継承用の{{extends}}タグと{{block}}タグをサポートするGoテンプレートのスーパーセットであるPongoを使用します。


4

私は何日もこの答えに戻ってきて、ついに弾丸を噛み、このための小さな抽象化レイヤー/プリプロセッサを書きました。それは基本的に:

  • 'extends'キーワードをテンプレートに追加します。
  • 'define'呼び出しのオーバーライドを許可します(したがって、greggoryのデフォルト値が可能です)
  • 定義されていない「テンプレート」呼び出しを許可します。空の文字列を指定するだけです。
  • のデフォルト値を設定します。'template'で。を呼び出します。親の

https://github.com/daemonl/go_sweetpl

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.