Nested Visiting

gjson supports hierarchical retrieval access to data content, with the default hierarchical separator being “.”. This feature makes it very convenient for developers to flexibly access unknown data structures.

Example 1, Basic Usage

  1. func main() {
  2. data :=
  3. `{
  4. "users" : {
  5. "count" : 2,
  6. "list" : [
  7. {"name" : "Ming", "score" : 60},
  8. {"name" : "John", "score" : 99.5}
  9. ]
  10. }
  11. }`
  12. if j, err := gjson.DecodeToJson(data); err != nil {
  13. panic(err)
  14. } else {
  15. fmt.Println("John Score:", j.Get("users.list.1.score"))
  16. }
  17. // Output:
  18. // John Score: 99.5
  19. }

As you can see, the gjson.Json object can retrieve the corresponding variable information through very flexible hierarchical filtering functions ( j.GetFloat32("users.list.1.score")).

Example 2, Custom Hierarchical Separator

  1. func main() {
  2. data :=
  3. `{
  4. "users" : {
  5. "count" : 2,
  6. "list" : [
  7. {"name" : "Ming", "score" : 60},
  8. {"name" : "John", "score" : 99.5}
  9. ]
  10. }
  11. }`
  12. if j, err := gjson.DecodeToJson(data); err != nil {
  13. panic(err)
  14. } else {
  15. j.SetSplitChar('#')
  16. fmt.Println("John Score:", j.Get("users#list#1#score"))
  17. }
  18. // Output:
  19. // John Score: 99.5
  20. }

As you can see, we can set our custom separator using the SetSplitChar method.

Example 3, Handling the Case Where Key Names Themselves Contain Hierarchical Symbols “.”

  1. func main() {
  2. data :=
  3. `{
  4. "users" : {
  5. "count" : 100
  6. },
  7. "users.count" : 101
  8. }`
  9. if j, err := gjson.DecodeToJson(data); err != nil {
  10. glog.Error(gctx.New(), err)
  11. } else {
  12. j.SetViolenceCheck(true)
  13. fmt.Println("Users Count:", j.Get("users.count"))
  14. }
  15. // Output:
  16. // Users Count: 101
  17. }

The result printed after running is 101. When the key name contains “.”, we can set conflict detection through SetViolenceCheck, and the retrieval priority will follow: key name->hierarchical, so there won’t be ambiguity. However, when the conflict detection switch is on, the retrieval efficiency will be lower, and it is off by default.

Precautions

As everyone knows, in Golang, the map/slice type is actually a “reference type” (also known as a “pointer type”), so when you modify the key-value/index items of this type of variable, it will also modify its corresponding underlying data.

For efficiency, the gjson package does not make value copies for the data type when some retrieval methods return map/slice, so when you modify the returned data, it will also modify the underlying data of gjson.

For example:

  1. func main() {
  2. jsonContent := `{"map":{"key":"value"}, "slice":[59,90]}`
  3. j, _ := gjson.LoadJson(jsonContent)
  4. m := j.Get("map")
  5. mMap := m.Map()
  6. fmt.Println(mMap)
  7. // Change the key-value pair.
  8. mMap["key"] = "john"
  9. // It changes the underlying key-value pair.
  10. fmt.Println(j.Get("map").Map())
  11. s := j.Get("slice")
  12. sArray := s.Array()
  13. fmt.Println(sArray)
  14. // Change the value of specified index.
  15. sArray[0] = 100
  16. // It changes the underlying slice.
  17. fmt.Println(j.Get("slice").Array())
  18. // output:
  19. // map[key:value]
  20. // map[key:john]
  21. // [59 90]
  22. // [100 90]
  23. }