How can I escape the output of a template?

2.1k views Asked by At

How do I escape an HTML snippet generated by a template? Like in this example:

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 does not do it automatically in my case. JSEscapeString through a func map also does not work (or I don’t know how), because I cannot call it like this {{jsescape (template "html-snippet" .)}}, since this is not a string.

Many thanks

1

There are 1 answers

0
icza On BEST ANSWER

You may register a function which executes the includable template and returns the result as a string. That string can then be inserted into the other template, proper context-sensitive escaping applied automatically:

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)
    }
}

Output (try it on the Go Playground):

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

Or even better: the template engine allows you to register functions that return 2 values (second of which must be an error), so our exect() function may look like this:

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

Output is the same. Try this one on the Go Playground.