有没有方便的方法来获取没有类型断言的JSON元素?

问题描述 投票:-4回答:2

处理来自Web服务器的JSON响应时存在一些不便。

例如,我不知道JSON的数据结构(并且不想建模),只是想从中获取值!

所以,对于Python,我可以写

value = response["body"][4]["data"]["uid"]  //response is a dictionary

但对于Golang,我需要对每个元素进行断言!

value := response["body"].([]interface{})[4].(map[string]interface{})["data"].(map[string]interface{})["uid"]
//response is a map[string]interface{}

这是我在golang中写的,以获得我需要的价值。你有什么建议吗?这种情况有什么有用的提示吗?

json dictionary go slice
2个回答
4
投票

如果使用结构对JSON对象建模并将其解组为该值,那么您不需要那些丑陋的索引和类型断言,您可以简单地引用结构字段。 请注意,您不必担心响应复杂,您只需要对要使用的部件进行建模。例如。如果响应是具有一百个字段但只需要2的对象,则创建仅包含这两个字段的结构。

如果您不想为JSON对象建模(或者不能因为它是动态的),那么您可以编写一个通用实用程序函数,它根据路径(一系列地图键和切片索引)获取一个值,您可以在这个答案中看到:Taking a JSON string, unmarshaling it into a map[string]interface{}, editing, and marshaling it into a []byte seems more complicated then it should be

最后,您可以使用已包含此帮助程序功能的第三方库,例如https://github.com/icza/dyno(披露:我是作者)。

使用github.com/icza/dyno,它看起来像这样:

value, err := dyno.Get(response, "body", 4, "data", "uid")

0
投票

根据icza,您可以为JSON对象创建结构。但是如果你得到JSON结构,你从一开始就不知道。然后,您可以使用对接口的反射创建动态解析,这将是一个解析JSON数据的递归函数。

func main(){
    var data interface{}
    err := json.Unmarshal([]bytes(file.json), &data)
    if err != nil {
        panic(err)
    }
    var itemData map[string]interface{}
    itemsMap := data.(map[string]interface{})
    jsonParsedObject := interate(itemsMap)  
    log.Println(jsonParsedObject)  
}

func iterate(data interface{}) interface{} {
    if reflect.ValueOf(data).Kind() == reflect.Slice {
        d := reflect.ValueOf(data)
        tmpData := make([]interface{}, d.Len())
        returnSlice := make([]interface{}, d.Len())
        for i := 0; i < d.Len(); i++ {
            tmpData[i] = d.Index(i).Interface()
        }
        for i, v := range tmpData {
            returnSlice[i] = iterate(v)
        }
        return returnSlice
    } else if reflect.ValueOf(data).Kind() == reflect.Map {
        d := reflect.ValueOf(data)
        tmpData := make(map[string]interface{})
        for _, k := range d.MapKeys() {
            typeOfValue := reflect.TypeOf(d.MapIndex(k).Interface()).Kind()
            if typeOfValue == reflect.Map || typeOfValue == reflect.Slice {
                tmpData[k.String()] = iterate(d.MapIndex(k).Interface())
            } else {
                tmpData[k.String()] = d.MapIndex(k).Interface()
            }
        }
        return tmpData
    }
    return data
}
© www.soinside.com 2019 - 2024. All rights reserved.