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

时间:2018-01-22 08:38:10

标签: json dictionary go slice

从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中写的,以获得我需要的值。你有什么建议吗?这种情况有什么有用的提示吗?

2 个答案:

答案 0 :(得分: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")

答案 1 :(得分: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
}