I have the following code which generates the following output
code:
package main
import (
"html/template"
"os"
)
type EntetiesClass struct {
Name string
Value int32
}
// In the template, we use rangeStruct to turn our struct values
// into a slice we can iterate over
var htmlTemplate = `{{range $index, $element := .}}
{{range $element}}{{.Name}}={{.Value}}
{{- end}}
{{- end}}`
func main() {
data := map[string][]EntetiesClass{
"Container1": {{"Test", 15}},
"Container2": {{"Test", 15}},
}
t := template.New("t")
t, err := t.Parse(htmlTemplate)
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, data)
if err != nil {
panic(err)
}
}
link: https://play.golang.org/p/yM9_wWmyLY
Output:
Test=15 Test=15
I want to compare the Container1 with Container2 and if they have common key, i just want to print output only once.
Output: Test=15
How can i achieve this? Any help is appreciated?
I can think of two ways to do this:
Dedup your data before passing to the template execution
This means you can pre-process the data before passing to t.Execute
to eliminate duplicates. You can do this using something like:
m := map[EntitiesClass]bool{}
for _, ... {
m[ec] = true
// Or maybe you want to aggregate "Container 1"
// and "Container 2" in some way
}
Then you can just pass the processed data and the template itself remains virtually unchanged
Add a custom function for your template
This means you can add a normal go function that receives as many EntitiesClass
as you like and returns them deduplicated (perhaps with the mechanism from option 1).
You can even do something like:
{{if not customHaveSeenThisValueBefore }}
...
{{ endif }}
For your simple example I would choose option 1, it seems easiest to leave templates very simple.
This applies some filtering logic. I'm using text/template
because this code isn't using a server. It will work the same with html/template
. When appending to slices of structs pointers have to be used. If you don't know why see here. func isInSlice() bool
needs to be modded to your needs. This serves as an example.
package main
import (
"os"
"text/template"
)
type Entitie struct {
Results []*Data
}
type Data struct {
Name string
Value int32
}
// Change this function to mod how to filter
func (e *Entitie) isInSlice(name string) bool {
for _, item := range e.Results {
if item.Name == name {
return true
}
}
return false
}
func (e *Entitie) AddData(name string, value int32) {
if !e.isInSlice(name) {
e.Results = append(e.Results, &Data{Name: name, Value: value})
}
}
// In the template, we use rangeStruct to turn our struct values
// into a slice we can iterate over
var template = `
{{range $i, $e := .Data.Results}}
{{$e.Name}} = {{$e.Value}}
{{end}}
`
func main() {
data := make(map[string]Entitie)
var entities Entitie
entities.AddData("test", 15)
entities.AddData("test", 15)
entities.AddData("test2", 15)
t := template.New("t")
t, err := t.Parse(template)
if err != nil {
panic(err)
}
data["Data"] = entities
err = t.Execute(os.Stdout, data)
if err != nil {
panic(err)
}
}