问题
I have a go template like this:
"environment": [
{{- range $k,$v := .env }}
{
"name": "{{ $k }}",
"value": "{{ $v }}"
},
{{- end }}
]
and i am getting the output below:
"environment": [
{
"name": "name",
"value": "test"
},
{
"name": "region",
"value": "us-east-1"
},
]
and i want to render it like below:
"environment": [
{
"name": "name",
"value": "bxbd"
},
{
"name": "region",
"value": "us-east-1"
}
]
I am not able to get rid of the last comma to make valid json. Or is it possible to somehow send the complete range block to some custom join function?
回答1:
Here's an example how to do it with templates, but I strongly recommend to use the 2nd approach if you want to generate JSON.
Sticking with templates
Since you're ranging over a map, you can't (simply) do it. In case of slices you could check the index variable (examples: Go template remove the last comma in range loop; and detect last item inside an array using range inside go-templates), but in case of maps you can't do that.
Knowing if you're at the first (or last) iteration is a state which you must maintain yourself. And example is to use custom functions or methods for this.
Here's an example implementation:
type Params struct {
Env map[string]string
Counter int
}
func (p *Params) IncMore() bool {
p.Counter++
return p.Counter < len(p.Env)
}
const src = `"environment": [
{{- range $k,$v := .Env }}
{
"name": "{{ $k }}",
"value": "{{ $v }}"
}{{if $.IncMore}},{{end}}
{{- end }}
]`
Testing it:
func main() {
t := template.Must(template.New("").Parse(src))
p := &Params{
Env: map[string]string{
"name": "test",
"region": "us-east-1",
},
}
err := t.Execute(os.Stdout, p)
if err != nil {
panic(err)
}
}
Output (try it on the Go Playground):
"environment": [
{
"name": "name",
"value": "test"
},
{
"name": "region",
"value": "us-east-1"
}
]
Use encoding/json
to generate JSON
If you're goal is to generate JSON, you should use the encoding/json package to generate valid JSON document. The above template has no knowledge about JSON syntax and context, and the values of the map entries are not escaped when written to the output, so you may still end up with invalid JSON.
Best would be to generate the JSON like this:
type Entry struct {
Name string `json:"name"`
Value string `json:"value"`
}
type Params struct {
Env []Entry `json:"environment"`
}
func main() {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ") // Optional
p := &Params{
Env: []Entry{
{Name: "name", Value: "test"},
{Name: "region", Value: "us-east-1"},
},
}
err := enc.Encode(p)
if err != nil {
panic(err)
}
}
Output (try it on the Go Playground):
{
"environment": [
{
"name": "name",
"value": "test"
},
{
"name": "region",
"value": "us-east-1"
}
]
}
来源:https://stackoverflow.com/questions/51043433/join-range-block-in-go-template