Dynamic hierarchical json parsing

I’m trying to find the best approach to decode a JSON structure that has two levels of embed node arrays (groups and group attributes). Here’s an example of the JSON structure

{
“name”: “name1”,
“birthyear”: 1984,
“location”: “USA”,
“groups”: [{
“group1”: [{
“group1_att1_name”: “gvalue1_1”
}, {
“group1_att2_name”: “gvalue1_2”
}]
}, {
“group2”: [{
“group2_att1_name”: “gvalue2_1”
}, {
“group2_att2_name”: “gvalue2_1”
}]
}, {
“group3”: [{
“group3_att1_name”: “gvalue3_1”
}, {
“group3_att2_name”: “gvalue3_1”
}]
}]
}

I’ve seen several examples of creating Go embedded structures to accommodate hierarchical node structures, but none that handle array situations like this. The examples I’ve seen require the Go struct elements to have variable naming convention that maps to the JSON, but I’m not sure how this would work. Look at the example above, it’s not as simple as naming a Struct element “Group1” because Group1 is a dynamic name that may or may not be in the JSON. clients submitting data in this JSON structure will all have different group names in different orders. Some will have the same, but at times groups won’t be present at all.

Thanks!

Something like gabs - https://github.com/Jeffail/gabs - may be better suited to this type of data.

Here is some working code:

package main

import (
	"encoding/json"
	"fmt"
	"log"
)

const exampleJSON = `{
    "name": "name1",
    "birthyear": 1984,
    "location": "USA",
    "groups":
    [
        {
            "group1":
            [
                {"group1_att1_name":"gvalue1_1"},
                {"group1_att2_name":"gvalue1_2"}
            ]
        },
        {
            "group2":
            [
                {"group2_att1_name":"gvalue2_1"},
                {"group2_att2_name":"gvalue2_1"}
            ]
        },
        {
            "group3":
            [
                {"group3_att1_name":"gvalue3_1"},
                {"group3_att2_name":"gvalue3_1"}
            ]
        }
    ]
}`

type myStruct struct {
	Name      string                                `json:"name"`
	BirthYear int                                   `json:"birthyear"`
	Location  string                                `json:"location"`
	Groups    []map[string][]map[string]interface{} `json:"groups"`
}

func main() {
	log.SetFlags(log.Lshortfile)

	var v myStruct
	err := json.Unmarshal([]byte(exampleJSON), &v)
	if err != nil {
		log.Fatalln(err)
	}

	fmt.Println("Name:", v.Name)
	fmt.Println("BirthYear:", v.BirthYear)
	fmt.Println("Location:", v.Location)

	// []....
	for _, g := range v.Groups {
		// map[string]...
		for group, h := range g {
			fmt.Printf("%v:\n", group)
			// []...
			for _, i := range h {
				// map[string]interface{}
				for attrName, attrValue := range i {
					fmt.Printf("\t%v: %v\n", attrName, attrValue)
				}
			}
		}
	}
}

Try it on the playground: https://play.golang.org/p/HhB-Xws9oW

I don’t know if this is the best approach or not because I don’t know what the data is meant to represent or how it will be used.

2 Likes

Thank you! This is what I was looking for.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.