เป็นไปได้ไหมที่จะมีเทมเพลตซ้อนใน Go โดยใช้ไลบรารีมาตรฐาน


88

ฉันจะรับเทมเพลตที่ซ้อนกันเช่น Jinja ใน python runtime ได้อย่างไร TBC สิ่งที่ฉันหมายถึงคือฉันจะมีเทมเพลตจำนวนมากที่สืบทอดมาจากเทมเพลตพื้นฐานได้อย่างไรเพียงแค่ยื่นในบล็อกของเทมเพลตพื้นฐานเช่น Jinja / django-templates เป็นไปได้ไหมโดยใช้เฉพาะhtml/templateในไลบรารีมาตรฐาน

หากนั่นไม่ใช่ความเป็นไปได้ทางเลือกของฉันคืออะไร หนวดดูเหมือนจะเป็นตัวเลือก แต่ถ้าอย่างนั้นฉันจะพลาดคุณสมบัติที่ละเอียดอ่อนเหล่านั้นhtml/templateเช่นการหลบหนีตามบริบท ฯลฯ หรือไม่? มีทางเลือกอื่นอะไรอีกบ้าง?

(สภาพแวดล้อม: Google App Engin, Go runtime v1, Dev - Mac OSx lion)

ขอบคุณที่อ่าน.

คำตอบ:


133

ใช่มันเป็นไปได้ A html.Templateคือชุดของไฟล์เทมเพลต หากคุณดำเนินการบล็อกที่กำหนดไว้ในชุดนี้บล็อกจะสามารถเข้าถึงบล็อกอื่น ๆ ทั้งหมดที่กำหนดไว้ในชุดนี้

หากคุณสร้างแผนที่ของชุดเทมเพลตดังกล่าวด้วยตัวคุณเองคุณจะมีความยืดหยุ่นเช่นเดียวกับที่ Jinja / Django เสนอ ข้อแตกต่างเพียงอย่างเดียวคือแพคเกจhtml / templateไม่มีการเข้าถึงระบบไฟล์โดยตรงดังนั้นคุณต้องแยกวิเคราะห์และเขียนเทมเพลตด้วยตัวคุณเอง

ลองพิจารณาตัวอย่างต่อไปนี้กับสองหน้าที่แตกต่างกัน ("index.html" และ "other.html") ที่ทั้งสองสืบทอดมาจาก "base.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 จะถูกแยกวิเคราะห์และจัดเก็บสองครั้ง คุณยังสามารถใช้ฟังก์ชัน Clone () ใน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

โปรดทราบว่าเมื่อคุณเรียกใช้แม่แบบพื้นฐานของคุณคุณต้องส่งผ่านค่าไปยังแม่แบบลูกที่นี่ฉันจะผ่าน "." เพื่อให้ทุกอย่างถูกส่งต่อ

template one แสดง {{.}}

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

แม่แบบสองแสดง {{.domains}} ที่ส่งผ่านไปยังแม่

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

โปรดทราบว่าหากเราใช้ {{template "content".}} แทน {{template "content".}} จะไม่สามารถเข้าถึง. โดเมนจากเทมเพลตเนื้อหาได้

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
ฉันก็เช่นกัน - ลองคิดดู :)
robert king

1
อะไร! ไม่อยากจะเชื่อเลยว่าจุดเล็ก ๆ ที่อยู่ท้ายตัวยึดตำแหน่ง {{template}} นั้นมีความหมายมาก เหตุใดจึงไม่มีการกล่าวถึงบนโลกนี้ในบทช่วยสอนหรือแม้แต่เอกสาร Go อย่างเป็นทางการ ?? ฉันรู้สึกท้อแท้ ... แต่ก็ดีใจมากที่พบคำตอบของคุณ! ขอบคุณมากตอนนี้แม่แบบของฉันมีหลายระดับของการซ้อนกันอย่างสวยงาม!
Gwyneth Llewelyn

แน่นอนสิ่งเดียวกับที่ฉันพยายามคิด!
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

ใช้Pongoซึ่งเป็นชุดเทมเพลต Go ขั้นสูงที่รองรับแท็ก {{expands}} และ {{block}} สำหรับการสืบทอดเทมเพลตเช่นเดียวกับ Django


4

ฉันกลับมาที่คำตอบนี้เป็นเวลาหลายวันในที่สุดก็บิตกระสุนและเขียนเลเยอร์นามธรรม / ตัวประมวลผลล่วงหน้าขนาดเล็กสำหรับสิ่งนี้ โดยพื้นฐานแล้ว:

  • เพิ่มคีย์เวิร์ด "ขยาย" ลงในเทมเพลต
  • อนุญาตให้แทนที่การเรียก 'กำหนด' (ดังนั้นค่าเริ่มต้นสำหรับ greggory จึงเป็นไปได้)
  • อนุญาตการเรียก 'template' ที่ไม่ได้กำหนดเพียงแค่ให้สตริงว่าง
  • ตั้งค่าเริ่มต้นของ. ใน 'template' เรียกไปที่ ของผู้ปกครอง

https://github.com/daemonl/go_sweetpl

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.