표준 라이브러리를 사용하여 Go에서 중첩 된 템플릿을 가질 수 있습니까?


87

Python 런타임에서 Jinja와 같은 중첩 템플릿을 얻으려면 어떻게해야합니까? TBC가 의미하는 바는 Jinja / django-templates처럼 기본 템플릿의 블록으로 파일을 작성하여 기본 템플릿에서 여러 템플릿을 상속받는 방법입니다. html/template표준 라이브러리 에서만 사용할 수 있습니까?

그것이 가능성이 아니라면 내 대안은 무엇입니까? 콧수염은 옵션 인 것 같지만 html/template상황에 맞는 이스케이프와 같은 멋진 미묘한 기능을 놓치고 있습니까? 다른 대안은 무엇입니까?

(환경 : Google App Engin, Go 런타임 v1, Dev-Mac OSx lion)

읽어 주셔서 감사합니다.

답변:


132

네 가능합니다. A html.Template는 실제로 템플릿 파일 집합입니다. 이 세트에서 정의 된 블록을 실행하면이 세트에 정의 된 다른 모든 블록에 액세스 할 수 있습니다.

이러한 템플릿 세트의 맵을 직접 생성하면 기본적으로 Jinja / Django가 제공하는 것과 동일한 유연성을 갖게됩니다. 유일한 차이점은 html / template 패키지는 파일 시스템에 직접 액세스 할 수 없으므로 직접 템플릿 을 구문 분석하고 구성해야한다는 것입니다.

둘 다 "base.html"에서 상속되는 두 개의 다른 페이지 ( "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
예를 들어 "head"에 대한 기본 데이터를 가질 수 있습니까?
— gregghz

18
여기서 호출해야하는 실제 템플릿을 렌더링하기 위해 여기에 추가하겠습니다 tmpl["index.html"].ExecuteTemplate(w, "base", data).
— hermansc

base.html은 두 번 구문 분석되고 저장됩니다. golang.org/pkg/text/template/#example_Template_share
— Maarten O.

3
중첩 템플릿에 데이터를 전달할 때 문제가 있습니다. 의 데이터 {{ .SomeData }}는 내부 템플릿에 표시되지 않습니다. 외부가 작동합니다.
— 0xAffe

경우는 중요 template.ParseFiles("index.html", "base.html")하다 template.ParseFiles("base.html", "index.html")?
— shackra

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

정확히, 제가 알아 내려고했던 것과 똑같은 것입니다!
— devforfu

5

다른 템플릿 패키지로 작업 한 후, 지금은 주로 표준 html / 템플릿 패키지로 작업하고 있는데, 그것이 제공하는 단순함과 다른 장점에 감사하지 않는 것이 순진하다고 생각합니다. 나는 다음과 같은 변경 사항으로 수락 된 답변에 매우 유사한 접근 방식을 사용합니다.

추가 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

나는 며칠 동안이 대답으로 돌아 왔고 마침내 총알을 깨물고 이것을 위해 작은 추상화 계층 / 사전 프로세서를 작성했습니다. 기본적으로 :

  • 템플릿에 '확장'키워드를 추가합니다.
  • '정의'호출 재정의 허용 (따라서 greggory에 대한 기본값이 가능함)
  • 정의되지 않은 '템플릿'호출을 허용하며 빈 문자열 만 제공합니다.
  • 의 기본값을 설정합니다. '템플릿'에서. 부모의

https://github.com/daemonl/go_sweetpl

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.