2

Using html/template to create JSON output. Code snippet is as follows (playground):

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "html/template"
)

const tpl = `
{
    "key": "{{- .Value -}}" // Replace with js .Value to get another error
}
`

func main() {
    t, err := template.New("").Parse(tpl)
    if err != nil {
        panic(err)
    }
    var buf bytes.Buffer
    err = t.Execute(&buf, struct{
        Value string
    }{"Test\\ > \\ Value"})
    if err != nil {
        panic(err)
    }
    data := make(map[string]string)
    err = json.Unmarshal(buf.Bytes(), &data)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%v\n", data)
}

If I try to insert .Value as is - then I get the following error:

panic: invalid character ' ' in string escape code

This is because \\ becomes \ and \ + space is incorrect escaping in JSON. I can fix this by adding js function to template:

const tpl = `
{
    "key": "{{- js .Value -}}"
}
`

In that case it fails with another error:

panic: invalid character 'x' in string escape code

This is because js function converts > sign to \x3c and \x is incorrect escaping in JSON.

Any ideas how to get a universal function that correctly escapes strings for JSON? Is there an alternative way (e.g. an external library) to create JSON templates considering all these difficulties?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
vania-pooh
  • 2,933
  • 4
  • 24
  • 42
  • Probably related to https://stackoverflow.com/questions/21482948/how-to-print-json-on-golang-template. – vania-pooh Jan 18 '19 at 08:58
  • 1
    The template engine doesn't know about JSON syntax. You should use `encoding/json` to generate JSON output. – icza Jan 18 '19 at 11:16
  • If you want to use templates, definitely use `text/template` not `html/template`, since the latter is (as the package name indicates) *specifically for HTML*. But really, `encoding/json` would be the more elegant solution for producing JSON. – Adrian Jan 18 '19 at 15:02

1 Answers1

2

Option 0

https://play.golang.org/p/4DMTAfEapbM

As @Adrian suggested, using text/template, so we do need just one unescape and the end.

Option 1

https://play.golang.org/p/oPC1E6s-EwB

Enscape before excute template, then unenscape twice when you want the string value.

Option 2

https://play.golang.org/p/zD-cTO07GZq

Replace "\\" with "\\\\".

}{"Test\\ > \\ Value"})
to
}{"Test\\\\ > \\\\ Value"})

one more

"// " comment is not supported in json.

Billy Yuan
  • 1,177
  • 7
  • 12