通用编解码-层级访问

层级访问

gjson 支持对数据内容进行层级检索访问,层级分隔符号默认为“ .”。该特性使得开发者可以灵活访问未知的数据结构内容变得非常简便。

示例1,基本使用

func main() {
    data :=
        `{
    "users" : {
        "count" : 2,
        "list"  : [
            {"name" : "Ming", "score" : 60},
            {"name" : "John", "score" : 99.5}
        ]
    }
}`
    if j, err := gjson.DecodeToJson(data); err != nil {
        panic(err)
    } else {
        fmt.Println("John Score:", j.Get("users.list.1.score"))
    }
    // Output:
    // John Score: 99.5
}

可以看到, gjson.Json 对象可以通过非常灵活的层级筛选功能( j.GetFloat32("users.list.1.score"))检索到对应的变量信息。

示例2,自定义层级分隔符号

func main() {
    data :=
        `{
    "users" : {
        "count" : 2,
        "list"  : [
            {"name" : "Ming", "score" : 60},
            {"name" : "John", "score" : 99.5}
        ]
    }
}`
    if j, err := gjson.DecodeToJson(data); err != nil {
        panic(err)
    } else {
        j.SetSplitChar('#')
        fmt.Println("John Score:", j.Get("users#list#1#score"))
    }
    // Output:
    // John Score: 99.5
}

可以看到,我们可以通过 SetSplitChar 方法设置我们自定义的分隔符号。

示例3,处理键名本身带有层级符号“ .”的情况

func main() {
    data :=
        `{
        "users" : {
            "count" : 100
        },
        "users.count" : 101
    }`
    if j, err := gjson.DecodeToJson(data); err != nil {
        glog.Error(gctx.New(), err)
    } else {
        j.SetViolenceCheck(true)
        fmt.Println("Users Count:", j.Get("users.count"))
    }
    // Output:
    // Users Count: 101
}

运行之后打印出的结果为 101。当键名存在“ .”号时,我们可以通过 SetViolenceCheck 设置冲突检测,随后检索优先级将会按照:键名->层级,便并不会引起歧义。但是当冲突检测开关开启时,检索效率将会变低,默认为关闭状态。

注意事项

大家都知道,在 Golang 里面, map/slice 类型其实是一个“引用类型”(也叫”指针类型“),因此当你对这种类型的变量 键值对/索引项 进行修改时,会同时修改到其对应的底层数据。

从效率上考虑, gjson 包某些获取方法返回的数据类型为 map/slice 时,没有对齐做值拷贝,因此当你对返回的数据进行修改时,会同时修改 gjson 对应的底层数据。

例如:

func main() {
    jsonContent := `{"map":{"key":"value"}, "slice":[59,90]}`
    j, _ := gjson.LoadJson(jsonContent)
    m := j.Get("map")
    mMap := m.Map()
    fmt.Println(mMap)

    // Change the key-value pair.
    mMap["key"] = "john"

    // It changes the underlying key-value pair.
    fmt.Println(j.Get("map").Map())

    s := j.Get("slice")
    sArray := s.Array()
    fmt.Println(sArray)

    // Change the value of specified index.
    sArray[0] = 100

    // It changes the underlying slice.
    fmt.Println(j.Get("slice").Array())

    // output:
    // map[key:value]
    // map[key:john]
    // [59 90]
    // [100 90]
}