Created
August 5, 2018 09:18
-
-
Save NaniteFactory/7a917e3e4442aa3c7d66d67b58007e21 to your computer and use it in GitHub Desktop.
Traverse / iterate over an unmarshalled JSON data in Golang.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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" | |
| } | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you, this helped me.