【问题标题】:Is there any convenient way to get JSON element without type assertion?有没有方便的方法来获取没有类型断言的 JSON 元素?
【发布时间】:2018-06-30 20:14:33
【问题描述】:

在处理来自网络服务器的 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 响应,我确定该模型在某处进行了描述。
  • 如果你的类型断言有效,那么你显然确实知道数据结构。
  • 其实我可以对它建模,但它是一种非常复杂的格式,它不是一个公共API,变化很大。所以我监控http请求/响应并编写代码来自动化它

标签: json dictionary go slice


【解决方案1】:

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

如果您不想为您的 JSON 对象建模(或者因为它是动态的而不能),那么您可以编写一个通用实用程序函数,该函数根据 path 获取一个值(一系列映射键和切片索引),您可以在此答案中看到: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

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

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

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

【讨论】:

    【解决方案2】:

    根据 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
    }
    

    【讨论】:

      猜你喜欢
      • 2020-12-12
      • 1970-01-01
      • 1970-01-01
      • 2018-08-30
      • 1970-01-01
      • 2020-02-10
      • 2019-03-20
      • 2021-07-19
      • 2022-12-07
      相关资源
      最近更新 更多