Jex’s Note

Golang Template

template 來源可以是字串也可以是一個檔案(html or text) 透過 html/template 或 text/template 將內容取代

取代的 HTML template 為字串

package main

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

const tmpl = `
<html>
    <head>
        <title></title>
    </head>
    <body>

    </body>
</html>`

func tHandler(w http.ResponseWriter, r *http.Request) {
    t := template.Must(template.New("ex").Parse(tmpl))
    v := map[string]interface{}{
        "Title": "Test <b>World</b>",
        "Body":  template.HTML("Hello <b>World</b>"),
    }
    t.Execute(w, v)
}

func main() {
    http.HandleFunc("/", tHandler)
    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

瀏覽器得到 server 輸出的內容 :

<html>
    <head>
        <title>Test &lt;b&gt;World&lt;/b&gt;</title>
    </head>
    <body>
        Hello <b>World</b>
    </body>
</html>

可以看到 title 跟 body 的結果截然不同, title 的 html 標籤會被轉義, 而 body 沒有是因為我加上了 template.HTML() 不要轉義 HTML 標籤, 我覺得預設轉義設計是很好的, 防止沒注意而產生了 XSS 漏洞, rails 也是預設轉義的, 但 php 什麼時候才要改!!!??? (怒

當改成 t.Execute(os.Stdout, v), 表示是系統的標準輸出, 所以只會在 terminal 上看到輸出, 瀏覽器則不會有任何內容

取代的 HTML template 為檔案

將 header 與 footer 做為固定的 template, 並傳入動態內容 :

func tHandler(w http.ResponseWriter, r *http.Request) {
    t, _ := template.ParseFiles("header.tmpl", "body.html", "footer.tmpl")
    var data = map[string] interface{}{
        "content" : "Do you copy?",
    }
    t.ExecuteTemplate(w, "body", data)
    t.Execute(w, nil)
}

header.tmpl :

<html>
<head>
    <title>Video downloader</title>
</head>
<body>

body.html :

<h1 id="go">Golang Web Works!</h1>

footer.tmpl :

</body>
</html>

最後在瀏覽器顯示的結果是 :

<html>
<head>
    <title>Video downloader</title>
</head>
<body>

<h1 id="go">Golang Web Works!</h1>
Do you copy?

</body>
</html>

副檔名不需要一定是 .html .tmpl, 你可以自訂任何你喜歡的 template.ParseFiles 只負責引入檔案而已, 而真正負責要呈獻出來的內容及 parse 是 t.ExecuteTemplate

For loop template

有時候我們會重覆使用同一個 template 連續印出10次, 作法如下

作法 1, 用 range 直接在 template 跑 10 次

view/nameList.tmpl :

Name list :

 -> 

func main :

var tmp bytes.Buffer
var data = map[string]interface{}{}
t, _ := template.ParseFiles(
    "view/nameList.tmpl",
)
data["nameList"] = []string{"Jex", "Bob"}
t.ExecuteTemplate(&tmp, "nameList", data)
fmt.Println(tmp.String())
作法2, 先跑 10 次的 template, 再將生成後的 html 傳到 body 再輸出

建立要重覆的 urlItem.tmpl :

<li id="url-"></li>

body.html :

<ul class="list-group">

</ul>

完整程式碼 :

// Show view
var tmplPath string = "view/template/"
var indexPath string = "view/index/"
t, _ := template.ParseFiles(
    tmplPath + "header.tmpl",
    indexPath + "body.html",
    tmplPath + "index/urlItem.tmpl",
    tmplPath + "footer.tmpl",
)

// For loop url item
var tmplBuf bytes.Buffer                            // 建立 buffer, 等等 for loop 的 template 都存>進來
var nums = map[string] interface{}{}                // 建立 data interface{}
for num := 1; num <= 10; num++ {
    nums["num"] = num
    t.ExecuteTemplate(&tmplBuf, "urlItem", nums)    // 將數字帶進 template
}
data["urlItem"] = template.HTML(tmplBuf.String())   // 將 for loop template 的結果存進 urlItem, 並>且不要 escape HTML Tag
t.ExecuteTemplate(w, "body", data)
t.Execute(w, nil)

ref : http://play.golang.org/p/Uw8l3M7Qvg https://groups.google.com/forum/#!topic/golang-nuts/8L4eDkr5Q84 http://blog.xcai.net/golang/templates

取代的 TEXT template 為檔案

// 讀取資料夾底下的 template (不需要指定檔名)
var emailBodyTemplates = template.Must(template.ParseGlob("app/template/email/en/*"))     // 資料夾底下有很多 .txt 的 template 檔案
var tmp bytes.Buffer
err = emailBodyTemplates.ExecuteTemplate(&tmp, templateName, replacement)
if err != nil {
    return
}

// 讀取檔案的 template (需要指定檔名)
var emailLayoutTemplates = template.Must(template.ParseFiles("app/template/layout/email.html"))
err = emailLayoutTemplates.Execute(&tmp, replacement)

不要脫逸 ' " 等 HTML 符號

template.HTML 包起來

improt "html/template"

var t = template.Must(template.New("ex").Parse(` pen.  pen.`))
data := map[string]interface{}{
    "name":  template.HTML("Tom's"),
    "name2": "Tom's",
}
t.ExecuteTemplate(os.Stdout, "ex", data)

result

Tom's pen. Tom&#39;s pen.

' -> &#39;

解法2: improt 改成 text/template, 就不需要用 template.HTML 防止脫逸了

Comments