如何逃避模板的输出?

时间:2016-12-20 00:18:50

标签: go escaping go-templates

如何转义模板生成的HTML代码段?就像在这个例子中一样:

package main

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

// I want to escape a html snippet which is then stored as a 
// javascript variable. how can I do that? the second output 
// is the one i would like to generate with a template.

var tmpl = `{{define "main"}}<script>var xx = "{{template "html-snippet" .}}";</script>{{end}}{{define "html-snippet"}}<div>
    <img src="{{.}}">
</div>{{end}}`

func main() {
    t, err := template.New("fo").Parse(tmpl)
    if err != nil {
        fmt.Println(err)
        return
    }
    t.ExecuteTemplate(os.Stdout, "main", "some.jpg")
    fmt.Println("")
    fmt.Println(template.JSEscapeString(`<div>
        <img src="some.jpg">
    </div`))
}

https://play.golang.org/p/TBJxYqokkU

在我的情况下,

html/template 自动执行此操作。 JSEscapeString通过功能映射也不起作用(或者我不知道如何),因为我不能像{{jsescape (template "html-snippet" .)}}那样调用它,因为这不是字符串。

非常感谢

1 个答案:

答案 0 :(得分:1)

您可以注册执行包含模板的函数,并将结果作为string返回。然后可以将string插入到另一个模板中,自动应用适当的上下文相关转义:

var tmpl = `{{define "main"}}<script>var xx = {{exect "html-snippet" .}};</script>{{end}}{{define "html-snippet"}}<div>
    <img src="{{.}}">
</div>{{end}}`

var t *template.Template

func exect(name string, data interface{}) string {
    buf := &bytes.Buffer{}
    if err := t.ExecuteTemplate(buf, name, data); err != nil {
        fmt.Println("Error:", err)
    }
    return buf.String()
}

func main() {
    t = template.Must(template.New("fo").Funcs(template.FuncMap{
        "exect": exect,
    }).Parse(tmpl))
    if err := t.ExecuteTemplate(os.Stdout, "main", "some.jpg"); err != nil {
        fmt.Println(err)
    }
}

输出(在Go Playground上尝试):

<script>var xx = "\u003cdiv\u003e\n\t\u003cimg src=\"some.jpg\"\u003e\n\u003c/div\u003e";</script>

甚至更好:模板引擎允许您注册返回2个值的函数(其中第二个必须是错误),因此我们的exect()函数可能如下所示:

func exect(name string, data interface{}) (string, error) {
    buf := &bytes.Buffer{}
    err := t.ExecuteTemplate(buf, name, data)
    return buf.String(), err
}

输出是一样的。在Go Playground上试试这个。