在go lang中循环/遍历第二级嵌套JSON

时间:2015-03-31 10:10:57

标签: json go

请考虑以下代码:

package main

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


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

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

    fmt.Println("\nReflect type of Parsing/Unmarshalling Error Object:\n",reflect.TypeOf(err))
    fmt.Println("\nParsing/Unmarshalling Error Object:\n",err)
    if err != nil {
        panic(err)
    }

    fmt.Println("\nParsed JSON is as follows:\n",m)
    fmt.Println("\nReflect type of parsed json object:\n", reflect.TypeOf(m))

    for firstLvlkey, firstLvlValue := range m { 
        fmt.Println("First Level Key:", firstLvlkey)
        fmt.Println("First Level Key reflect type of :", reflect.TypeOf(firstLvlkey))

        fmt.Println("First Level Value:", firstLvlValue)
        fmt.Println("First Level Value reflect type of :", reflect.TypeOf(firstLvlValue))
         // <===============================>
         //Here I want to iterate/loop over innerJSON1, InnerJSON2 then reach to level InnerInnerJSONArray - fld1 and fld2
         // <===============================>

    }
}

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

我有一些要求,比如我想要读取/获取String类型中的所有Key和值以进行某些处理adn我无法定义struct因为我将获得动态JSON输入(例如InnerInnerArray作为字符串,然后第二级循环将给出数组索引并处理每个具有键fld1val1的JSON。

我希望迭代其中包含的每个键/值对,通过地图的最有效方法是什么?

注意:我是Go-lang的新手,您的建议/改进也是最受欢迎的。

4 个答案:

答案 0 :(得分:15)

请参阅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"
    }
}
`

这将打印:

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

关键是在使用接口类型时必须使用类型断言。类型开关可以根据需要轻松确定类型。代码将以递归方式遍历任何嵌套数组或映射,以便您可以添加任意数量的级别并获取所有值。

答案 1 :(得分:2)

您需要解析JSON,然后通过结构递归检查所包含值的类型并以某种方式处理它们。

下面的示例函数采用*interface{}(指向任何类型的指针)和字符串,int和对象指针的处理函数,它生成它发现的项目:

func eachJsonValue(obj *interface{}, handler func(*string, *int, *interface{})) {
  if obj == nil {
    return
  }
  // Yield all key/value pairs for objects.
  o, isObject := (*obj).(map[string]interface{})
  if isObject {
    for k, v := range o {
      handler(&k, nil, &v)
      eachJsonValue(&v, handler)
    }
  }
  // Yield each index/value for arrays.
  a, isArray := (*obj).([]interface{})
  if isArray {
    for i, x := range a {
      handler(nil, &i, &x)
      eachJsonValue(&x, handler)
    }
  }
  // Do nothing for primitives since the handler got them.
}

如下所示调用它将打印列出的结果。当然,你的处理函数可以用已知的键/值做一些特殊的事情,例如&#34; fld1&#34;:

func main() {
  // Parse the JSON.
  var obj interface{}
  json.Unmarshal([]byte(input), &obj) // XXX: check the error value.

  // Handle object key/value pairs and array index/items.
  eachJsonValue(&obj, func(key *string, index *int, value *interface{}) {
    if key != nil { // It's an object key/value pair...
      fmt.Printf("OBJ: key=%q, value=%#v\n", *key, *value)
    } else { // It's an array item...
      fmt.Printf("ARR: index=%d, value=%#v\n", *index, *value)
    }
  })
}

// OBJ: key="outterJSON", value=map[string]interface {}{...}
// OBJ: key="innerJSON1", value=map[string]interface {}{...}
// OBJ: key="value1", value=10
// OBJ: key="value2", value=22
// OBJ: key="InnerInnerArray", value=[]interface {}{...}
// ARR: index=0, value="test1"
// ARR: index=1, value="test2"
// OBJ: key="InnerInnerJSONArray", value=[]interface {}{...}
// ARR: index=0, value=map[string]interface {}{...}
// OBJ: key="fld1", value="val1"
// ARR: index=1, value=map[string]interface {}{...}
// OBJ: key="fld2", value="val2"
// OBJ: key="InnerJSON2", value="NoneValue"

答案 2 :(得分:2)

有相关问题herehere(可能还有其他问题)。

有一些更复杂的JSON解析API可以让您的工作更轻松。一个例子是stretchr/objx

使用objx的一个例子:

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

当你真的不知道JSON结构是什么时,这是有效的。但是,如果您提前知道JSON输入的结构,首选方法是使用结构描述它并使用标准API进行编组。

答案 3 :(得分:0)

我已经实现了与https://stackoverflow.com/users/1078890/iamnan解决方案非常相似的方法。 parseMapparseArray的主体合并为一个,看起来像这样。

func printJson(res1 map[string]interface{}, res2 []interface{}) {
    for k, v := range res1 {
        switch vv := v.(type) {
        case float64, int, string:
            fmt.Println(k, ":", vv)
        case []interface{}:
            fmt.Println(k, ":")
            printJson(nil, vv)
        case map[string]interface{}:
            fmt.Println(k, ":")
            printJson(vv, nil)
        default:
            fmt.Println(k, ":", vv)
        }
    }
    for k, v := range res2 {
        switch vv := v.(type) {
        case float64, int, string:
            fmt.Println(k, ":", vv)
        case []interface{}:
            fmt.Println(k, ":")
            printJson(nil, vv)
        case map[string]interface{}:
            fmt.Println(k, ":")
            printJson(vv, nil)
        default:
            fmt.Println(k, ":", vv)
        }
    }
}

可以在这里https://gist.github.com/sandeep-sarkar/78a0e96461b4dec727386a96404d29b0

找到代码