[go]一个简易的获取json中某个层级字段对应的值的工具函数

背景

师弟在项目中有这样一个需求,需要拿到json格式的响应报文中的某个字段(key)对应的值,这个值会出现在不同响应中的不同嵌套位置中,而且在某个响应中,同名的字段在不同的嵌套层级可能会出现多次,所以对于每个具体响应,需要使用某个规则的字符串来指出嵌套的位置,比如 key1.key2.key3

 

实现思路

json的结构其实很像一棵树,某个子节点要么键对应的是一个值要么是一个子json,需要很适合使用dfs进行遍历

其中只需要对反序列化后的子节点进行类型断言即可,这里需要特别注意一下,如果子json字段是一个切片,那么类型断言对应的应该是[]interface{} 而不是 []map[string]interface{}

ps:map[string]interface{} 简直就是json的别名

最后以 key1.key2.key2.0.key4 这种结构就可以取到对应的值,其中数字代表在上一个子字段为切片类型中的第几个

 

代码

实现代码如下


func main() {

    req := `{
        "ch": "market.btcusdt.trade.detail",
        "status": "ok",
        "ts": 1669874392880,
        "tick": {
            "id": 161221899829,
            "ts": 1669874391168,
            "data": [{
                "id": 161221899829685319577085771,
                "ts": 1669874391168,
                "trade-id": 102749823404,
                "amount": 9.34E-4,
                "price": 17115.82,
                "direction": "sell",
                "data":[{
                    "id": 161221899829685319577085323,
                    "ts": 2229874391168,
                    "trade-id": 222749823404,
                    "amount": 3.34E-4,
                    "price": 33115.82,
                    "direction": "sell"
                }]
            },{
                "id": 161221899829685319577085323,
                "ts": 2229874391168,
                "trade-id": 222749823404,
                "amount": 3.34E-4,
                "price": 33115.82,
                "direction": "sell"
            }]
        }
    }`


    js := map[string]interface{}{}

    json.Unmarshal([]byte(req), &js)


    tar := "tick.data.0.data.0.price"

    fmt.Println(getTargetItem(tar, js))
}

func getTargetItem(tarKey string, js map[string]interface{}) string {

    index := strings.Split(tarKey, ".")

    var ans string

    var dfs func(idx int, key string, mp map[string]interface{})

    dfs = func(idx int, key string, mp map[string]interface{}) {

        for k, v := range mp {

            if k == key {

                // if price, ok := v.(float64); ok {
                //  fmt.Println(price)
                //  return
                // }

                switch price := v.(type) {
                case string:
                    ans = price
                    return
                case float64:
                    ans = fmt.Sprintf("%f", price)
                    return
                default:

                }

                if nextMp, ok := v.(map[string]interface{}); ok {

                    dfs(idx+1, index[idx+1], nextMp)

                } else if dataSlice, ok := v.([]interface{}); ok {

                    num, err := strconv.Atoi(index[idx+1])
                    if err != nil {
                        fmt.Println(err.Error())
                    }

                    if nextP, ok := dataSlice[num].(map[string]interface{}); ok {
                        dfs(idx+2, index[idx+2], nextP)
                    }

                }

            }

        }

    }

    dfs(0, index[0], js)

    if ans != "" {
        return ans
    }
    return "not found"
}
点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注