Why am I seeing ZgotmplZ in my Go HTML template output?
Asked Answered
C

7

43

When I'm calling a Go template function to output HTML, it displays ZgotmplZ.

Sample code:

http://play.golang.org/p/tfuJa_pFkm

package main

import (
    "html/template"
    "os"
)

func main() {
    funcMap := template.FuncMap{
        "printSelected": func(s string) string {
            if s == "test" {
                return `selected="selected"`
            }
            return ""
        },

        "safe": func(s string) template.HTML {
            return template.HTML(s)
        },
    }
    template.Must(template.New("Template").Funcs(funcMap).Parse(`
    <option {{ printSelected "test" }} {{ printSelected "test" | safe }} >test</option>
    `)).Execute(os.Stdout, nil)

}

Output:

<option ZgotmplZ ZgotmplZ >test</option>
Circuity answered 8/2, 2013 at 3:51 Comment(0)
C
42

"ZgotmplZ" is a special value that indicates that unsafe content reached a CSS or URL context at runtime. The output of the example will be:

<img src="#ZgotmplZ">

You can add a safe and attr function to the template funcMap:

package main

import (
    "html/template"
    "os"
)

func main() {
    funcMap := template.FuncMap{
        "attr": func(s string) template.HTMLAttr {
            return template.HTMLAttr(s)
        },
        "safe": func(s string) template.HTML {
            return template.HTML(s)
        },
    }

    template.Must(template.New("Template").Funcs(funcMap).Parse(`
    <option {{.attr | attr}}>test</option>
        {{.html | safe}}
     `)).Execute(os.Stdout, map[string]string{
        "attr": `selected="selected"`,
        "html": `<option selected="selected">option</option>`,
    })
}

The output will look like:

<option selected="selected">test</option>
<option selected="selected">option</option>

You may want to define some other functions which can convert string to template.CSS, template.JS, template.JSStr, template.URL etc.

Cherokee answered 10/2, 2013 at 10:11 Comment(5)
This doesn't work either, FYI (for a function that takes input and uses it in the output).Circuity
safe can let you display raw html in template.Cherokee
Use template.HTMLAttr instead of template.HTML, it work fine. see updated code.Cherokee
This works, thanks. Demonstrated for posterity: play.golang.org/p/nq3-7GYAoYCircuity
function iteral is unessaryDiseased
C
12

I had similar problem with <img src="{{myfunction}}"> where myfunction return encoded image.

Finally I solved it when instead of string function return template.URL(mystring).

Chiaki answered 18/10, 2015 at 18:7 Comment(0)
G
8
package main

import (
    "html/template"
    "os"
)

type T struct {
    HTML template.HTML
    ATTR template.HTMLAttr
    URL  template.URL
    JS   template.JS
    CSS  template.CSS
}

func main() {

    data := T{
        HTML: `<div>test div</div>`,
        ATTR: `selected="selected"`,
        URL:  `https://upload.wikimedia.org/wikipedia/commons/5/53/Google_%22G%22_Logo.svg`,
        CSS:  `font-size: 15px`,
        JS:   `console.log("hello world")`,
    }

    template.Must(template.New("Template").Parse(`
        {{.HTML}}
        <option {{.ATTR}} style="{{.CSS}}">test</option>
        <script>{{.JS}}</script>
        <img src="{{.URL}}">
    `)).Execute(os.Stdout, data)
}

output

<div>test div</div>
<option selected="selected" style="font-size: 15px">test</option>
<script>console.log("hello world")</script>
<img src="https://upload.wikimedia.org/wikipedia/commons/5/53/Google_%22G%22_Logo.svg">

playground Example

Glottochronology answered 7/10, 2019 at 20:46 Comment(0)
C
5

You are trying to output HTML in a place where template/html thinks is unsafe (for example, inside an HTML element, like this:

<option {{ printSelected }}>

I cannot find any way to convince it it is safe (including returning template.HTML instead of string); the only alternative I have found is to rewrite the template, in this example use a bool output instead:

<option {{ if printSelected }}selected{{ end }}>
Circuity answered 8/2, 2013 at 3:51 Comment(1)
Personally, I prefer your suggestion, for a simple reason: notwithstanding all the other correct answers, yours — while possibly 'more verbose' — is the only one that guarantees that unsafe content will never reach the template. This, IMHO, should be the best way of doing things. Any tricks or hacks which rely on 'fooling' Go to accept potential unsafe code is... well, not safe, is it?Vitreous
F
3

easiest way:

import "html/template"
yourhref = template.URL(yourhref)
Fredelia answered 25/1, 2018 at 13:39 Comment(1)
This is the correct answer if you want to render text into href attribute like: <a href="{{.Host}}">Hi</a>, Host should be template.URL to avoid ZgotmplZ.Holley
O
2

You should wrap the string in an HTMLAttr, which was designed for text that gets injected in between angle brackets. Per the documentation:

https://golang.org/pkg/html/template/#HTMLAttr

HTMLAttr encapsulates an HTML attribute from a trusted source, for example,  dir="ltr".

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will be included verbatim in the template output.

type HTMLAttr string

Odette answered 12/6, 2018 at 17:59 Comment(1)
Thanks for citing the docs. Put me in the right direction.Eclampsia
G
0

I was trying to insert an image from frontmatter into my template but kept getting the same error. I solved it thus:

{{ if isset .Params "image" }}
    {{ $myVar := print .Params.image }}
    <img src="{{ $myVar }}">
{{ end }}

Notice that I first save the .Params.image as a variable, and then insert it as my src.

Gers answered 30/11, 2022 at 0:34 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.