请考虑以下代码:
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
作为字符串,然后第二级循环将给出数组索引并处理每个具有键fld1
和val1
的JSON。
我希望迭代其中包含的每个键/值对,通过地图的最有效方法是什么?
注意:我是Go-lang的新手,您的建议/改进也是最受欢迎的。
答案 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)
有一些更复杂的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解决方案非常相似的方法。 parseMap
和parseArray
的主体合并为一个,看起来像这样。
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
找到代码