Skip to content

Instantly share code, notes, and snippets.

@NaniteFactory
Created August 5, 2018 09:18
Show Gist options
  • Select an option

  • Save NaniteFactory/7a917e3e4442aa3c7d66d67b58007e21 to your computer and use it in GitHub Desktop.

Select an option

Save NaniteFactory/7a917e3e4442aa3c7d66d67b58007e21 to your computer and use it in GitHub Desktop.
Traverse / iterate over an unmarshalled JSON data in Golang.
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
)
// To unmarshal JSON into an interface value,
// json.Unmarshal() stores one of these in the interface value:
//
// bool, for JSON booleans
// float64, for JSON numbers
// string, for JSON strings
// []interface{}, for JSON arrays
// map[string]interface{}, for JSON objects
// nil for JSON null
// CopyUnmarshalled performs deep copy to an unmarshalled json data.
func CopyUnmarshalled(src interface{}) (dst interface{}, err error) {
switch src.(type) {
case nil:
return nil, nil
case bool:
dst = src.(bool)
case float64:
dst = src.(float64)
case string:
dst = src.(string)
case []interface{}:
arr, err := copyUnmarshalledArray(src.([]interface{}))
if err != nil {
return nil, err
}
dst = arr
case map[string]interface{}:
obj, err := copyUnmarshalledObject(src.(map[string]interface{}))
if err != nil {
return nil, err
}
dst = obj
default:
return nil, errors.New("unknown type")
}
return dst, nil
}
func copyUnmarshalledArray(src []interface{}) (dst []interface{}, err error) {
dst = make([]interface{}, len(src))
for i, e := range src {
switch e.(type) {
case nil:
return nil, nil
case bool, float64, string:
dst[i] = e
case []interface{}:
dst[i], err = copyUnmarshalledArray(e.([]interface{}))
if err != nil {
return nil, err
}
case map[string]interface{}:
dst[i], err = copyUnmarshalledObject(src[i].(map[string]interface{}))
if err != nil {
return nil, err
}
default:
return nil, errors.New("unknown type")
}
}
return dst, nil
}
func copyUnmarshalledObject(src map[string]interface{}) (dst map[string]interface{}, err error) {
dst = map[string]interface{}{}
for key, value := range src {
switch src[key].(type) {
case nil:
return nil, nil
case bool, float64, string:
dst[key] = value
case []interface{}:
dst[key], err = copyUnmarshalledArray(src[key].([]interface{}))
if err != nil {
return nil, err
}
case map[string]interface{}:
dst[key], err = copyUnmarshalledObject(src[key].(map[string]interface{}))
if err != nil {
return nil, err
}
default:
return nil, errors.New("unknown type")
}
}
return dst, nil
}
func PrintUnmarshalled(w io.Writer, src interface{}) {
switch src.(type) {
case []interface{}:
printUnmarshalledArray(w, src.([]interface{}), 0)
case map[string]interface{}:
printUnmarshalledObject(w, src.(map[string]interface{}), 0)
default:
fmt.Fprintln(w, fmt.Sprint(src))
}
}
func printUnmarshalledArray(w io.Writer, src []interface{}, nTabs int) {
tabs := ""
for i := 0; i < nTabs; i++ {
tabs += "\t"
}
fmt.Fprintln(w, tabs+"[")
for i, e := range src {
comma := ","
if i == len(src)-1 {
comma = ""
}
switch e.(type) {
case []interface{}:
printUnmarshalledArray(w, src[i].([]interface{}), nTabs+1)
fmt.Fprintln(w, tabs+comma)
case map[string]interface{}:
printUnmarshalledObject(w, src[i].(map[string]interface{}), nTabs+1)
fmt.Fprintln(w, tabs+comma)
default:
fmt.Fprintln(w, tabs+fmt.Sprint(e)+comma)
}
}
fmt.Fprintln(w, tabs+"]")
}
func printUnmarshalledObject(w io.Writer, src map[string]interface{}, nTabs int) {
tabs := ""
for i := 0; i < nTabs; i++ {
tabs += "\t"
}
fmt.Fprintln(w, tabs+"{")
i := 0
for key, value := range src {
comma := ","
if i == len(src)-1 {
comma = ""
}
switch src[key].(type) {
case []interface{}:
fmt.Fprintln(w, tabs+"\""+key+"\""+":")
printUnmarshalledArray(w, src[key].([]interface{}), nTabs+1)
fmt.Fprintln(w, tabs+comma)
case map[string]interface{}:
fmt.Fprintln(w, tabs+"\""+key+"\""+":")
printUnmarshalledObject(w, src[key].(map[string]interface{}), nTabs+1)
fmt.Fprintln(w, tabs+comma)
default:
fmt.Fprintln(w, tabs+"\""+key+"\":", "\""+fmt.Sprint(value)+"\""+comma)
}
i++
} // for
fmt.Fprintln(w, tabs+"}")
}
func main() {
var map1 interface{}
var map2 interface{}
jsonRaw := []byte(`{
"1": 2,
"hello": "world",
"foo": {
"1": 2,
"hello": "world",
"foo": {
"1": 2,
"hello": "world",
"foo": "bar"
},
"foo2": {
"1": 2,
"hello": "world",
"foo": "bar",
"list": [1, 2, 3, 4, 5, {"foo": "bar"}]
}
}
}`)
json.Unmarshal(jsonRaw, &map1)
fmt.Println(map1) // map[1:2 hello:world foo:map[1:2 hello:world foo:map[1:2 hello:world foo:bar] foo2:map[hello:world foo:bar list:[1 2 3 4 5 map[foo:bar]] 1:2]]]
fmt.Println(map2) // <nil>
fmt.Println()
map2, _ = CopyUnmarshalled(map1)
fmt.Println(map1) // map[1:2 hello:world foo:map[foo2:map[list:[1 2 3 4 5 map[foo:bar]] 1:2 hello:world foo:bar] 1:2 hello:world foo:map[1:2 hello:world foo:bar]]]
fmt.Println(map2) // map[foo:map[foo:map[1:2 hello:world foo:bar] foo2:map[list:[1 2 3 4 5 map[foo:bar]] 1:2 hello:world foo:bar] 1:2 hello:world] 1:2 hello:world]
fmt.Println()
map1.(map[string]interface{})["foo"].(map[string]interface{})["foo"].(map[string]interface{})["1"] =
"!!!!!!!!!!!!!!!!!!!!!!!"
fmt.Println(map1) // map[1:2 hello:world foo:map[foo:map[1:!!!!!!!!!!!!!!!!!!!!!!! hello:world foo:bar] foo2:map[1:2 hello:world foo:bar list:[1 2 3 4 5 map[foo:bar]]] 1:2 hello:world]]
fmt.Println(map2) // map[foo:map[1:2 hello:world foo:map[hello:world foo:bar 1:2] foo2:map[1:2 hello:world foo:bar list:[1 2 3 4 5 map[foo:bar]]]] 1:2 hello:world]
fmt.Println()
PrintUnmarshalled(os.Stdout, map2)
}
/*
{
"foo":
{
"foo2":
{
"1": "2",
"hello": "world",
"foo": "bar",
"list":
[
1,
2,
3,
4,
5,
{
"foo": "bar"
}
]
}
,
"1": "2",
"hello": "world",
"foo":
{
"1": "2",
"hello": "world",
"foo": "bar"
}
}
,
"1": "2",
"hello": "world"
}
*/
@btoll

btoll commented Apr 24, 2022

Copy link
Copy Markdown

Thank you, this helped me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment