Looping/iterate over the second level nested JSON in go lang

See this blog entry which thoroughly covers this subject, specifically the section Decoding arbitrary data. Using that you can do something like this: (playground example)

package main

import (
    "encoding/json"
    "fmt"    
)

func main() {
    // Creating the maps for JSON
    m := map[string]interface{}{}

    // Parsing/Unmarshalling JSON encoding/json
    err := json.Unmarshal([]byte(input), &m)

    if err != nil {
        panic(err)
    }
    parseMap(m)
}

func parseMap(aMap map[string]interface{}) {
    for key, val := range aMap {
        switch concreteVal := val.(type) {
        case map[string]interface{}:
            fmt.Println(key)
            parseMap(val.(map[string]interface{}))
        case []interface{}:
            fmt.Println(key)
            parseArray(val.([]interface{}))
        default:
            fmt.Println(key, ":", concreteVal)
        }
    }
}

func parseArray(anArray []interface{}) {
    for i, val := range anArray {
        switch concreteVal := val.(type) {
        case map[string]interface{}:
            fmt.Println("Index:", i)
            parseMap(val.(map[string]interface{}))
        case []interface{}:
            fmt.Println("Index:", i)
            parseArray(val.([]interface{}))
        default:
            fmt.Println("Index", i, ":", concreteVal)

        }
    }
}

const input = `
{
    "outterJSON": {
        "innerJSON1": {
            "value1": 10,
            "value2": 22,
            "InnerInnerArray": [ "test1" , "test2"],
            "InnerInnerJSONArray": [{"fld1" : "val1"} , {"fld2" : "val2"}]
        },
        "InnerJSON2":"NoneValue"
    }
}
`

This will print:

    //outterJSON
    //innerJSON1
    //InnerInnerJSONArray
    //Index: 0
    //fld1 : val1
    //Index: 1
    //fld2 : val2
    //value1 : 10
    //value2 : 22
    //InnerInnerArray
    //Index 0 : test1
    //Index 1 : test2
    //InnerJSON2 : NoneValue

The key thing is that you have to use type assertion when working with interface types. The type switch makes it easy to determine the type as needed. The code will recursively range through any nested array or map so you can add as many levels as you wish and get all your values.


There are related questions here and here (and possibly others).

There are some more sophisticated JSON parsing APIs that make your job easier. An example is stretchr/objx.

An example of using objx:

document, err := objx.FromJSON(json)
// TODO handle err
document.Get("path.to.field[0].you.want").Str()

This works when you really don't know what the JSON structure will be. However, if you do know the structure of your JSON input ahead of time, the preferred way is to describe it with structs and use the standard API for marshalling.

Tags:

Json

Go