Basic overview
People who have used dynamic languages believe that it is very easy to parse JSON. You only need a few lines of code to get the parsed JSON object. For example, Python parses JSON as follows
result = {"name": "Bob", "age": 18} print(result["name"]) // "Bob"
The simple data structure in Golang language can use map[string]interface {}, but if the JSON nesting format is too complex, it is particularly easy to get around in this way. If the struct structure is defined in advance, when the data is parsed into the structure with json.Unmarshal, the corresponding data is taken out, and the code amount will increase a lot. As shown below
type Student struct { Name string `json:"name"` Age int `json:"age"` } jsonData := []byte(` { "name": "Bob", "age": 18 }`) var student Student err := json.Unmarshal(jsonData, &student) if err != nil { fmt.Println(err) } fmt.Println(student.Name)
After comparison, I found that there is a relatively simple way for GoLang to parse JSON. As a language with such a wide audience, there must be a solution. Here is a grand introduction to the third-party package GJSON.
GJSON is a Go package that provides a quick and easy way to get values from JSON documents. It has functions such as single line retrieval, point symbol path, iteration and parsing JSON lines. Project address: https://github.com/tidwall/gjson
GJSON gets the value of JSON, which is relatively simple. The operation is as follows
package main import "github.com/tidwall/gjson" const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}` func main() { value := gjson.Get(json, "name.last") println(value.String()) // Prichard }
After comparison, it is found that the way GJSON obtains values is relatively simple. GJSON also supports simple path syntax to get values. The specific usage will be described in detail below
install
To use GSON, you first need to install Go and then execute the following go get command
$ go get -u github.com/tidwall/gjson
Usage mode
1, Path syntax
The following is a quick overview of path syntax, see GJSON syntax for more complete information. A path is a series of keys separated by points. ==The key may contain special wildcards' * 'and'? '. To access array values, use the index as the key. To get the number of elements in the array or access the subpath, use the # character. Points and wildcards can be escaped with '\'. = =
package main import ( "fmt" "github.com/tidwall/gjson" ) const json = ` { "name": {"first": "Tom", "last": "Anderson"}, "age":37, "children": ["Sara","Alex","Jack"], "fav.movie": "Deer Hunter", "friends": [ {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]}, {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]}, {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]} ] } ` func main() { // Get a value value1 := gjson.Get(json, "age") fmt.Println(value1) // 37 value2 := gjson.Get(json, "name.last") fmt.Println(value2) // Anderson value3 := gjson.Get(json, "name.first") fmt.Println(value3) // Tom value4 := gjson.Get(json, "children") fmt.Println(value4) // ["Sara","Alex","Jack"] // Total number of children array (number of elements) value5 := gjson.Get(json, "children.#") fmt.Println(value5) // 3 // The second element of the children array value6 := gjson.Get(json, "children.1") fmt.Println(value6) // Alex // *Represents any character (including 0) value7 := gjson.Get(json, "child*.2") fmt.Println(value7) // Jack // ? represents 0 or 1 characters value8 := gjson.Get(json, "c?ildren.0") fmt.Println(value8) // Sara // \Meaning escape value9 := gjson.Get(json, "fav\\.movie") fmt.Println(value9) // Deer Hunter value10 := gjson.Get(json, "friends.#.first") fmt.Println(value10) // ["Dale","Roger","Jane"] value11 := gjson.Get(json, "friends.1.last") fmt.Println(value11) // Craig /* You can also use # (...) to query the first match in the array, or use # (...) # - to find all matches. Query support = =,! =, < and < =, > and > = comparison operators, as well as simple pattern matching support of% (similar) and!% (not similar). */ // Find the first match in the array value12 := gjson.Get(json, `friends.#(last=="Murphy").first`) fmt.Println(value12) // Dale // Find all matches in the array value13 := gjson.Get(json, `friends.#(last=="Murphy")#.first`) fmt.Println(value13) // ["Dale","Jane"] // Find all last values with age greater than 45 in friends array value14 := gjson.Get(json, `friends.#(age>45)#.last`) fmt.Println(value14) // ["Craig","Murphy"] // The first value in the friends array is the last value starting with D value15 := gjson.Get(json, `friends.#(first%"D*").last`) fmt.Println(value15) // Murphy // The first value in the friends array is the last value that does not start with D value16 := gjson.Get(json, `friends.#(first!%"D*").last`) fmt.Println(value16) // Craig // Find the value of nets array in friends array contains fb value17 := gjson.Get(json, `friends.#(nets.#(=="fb"))#.first`) fmt.Println(value17) // ["Dale","Roger"] }
2, Get nested array value
package main import ( "fmt" "github.com/tidwall/gjson" ) const json = ` { "programmers": [ { "firstName": "Janet", "lastName": "McLaughlin", }, { "firstName": "Elliotte", "lastName": "Hunter", }, { "firstName": "Jason", "lastName": "Harold", } ] } ` func main(){ // Get nested array value result := gjson.Get(json, "programmers.#.lastName") for _, name := range result.Array() { println(name.String()) // prints McLaughlin Hunter Harold } // Querying objects in an array name := gjson.Get(json, `programmers.#(lastName="Hunter").firstName`) println(name.String()) // prints "Elliotte" // Traversal object or array result.ForEach(func(key, value gjson.Result) bool { println(value.String()) return true // keep iterating })
3, Simple use of Parse and Get
The following three writing methods will get the same result
package main import ( "fmt" "github.com/tidwall/gjson" ) const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}` func main(){ value1 := gjson.Parse(json).Get("name").Get("last") fmt.Println(value1) // Prichard value2 := gjson.Get(json, "name").Get("last") fmt.Println(value2) // Prichard value3 := gjson.Get(json, "name.last") fmt.Println(value3) // Prichard // Check whether the value already exists value := gjson.Get(json, "name.last") if !value.Exists() { println("no last name") } else { println(value.String()) // Prichard } // Or as one step if gjson.Get(json, "name.last").Exists() { println("has a last name") // has a last name } // Verify whether it is json if !gjson.Valid(json) { fmt.Println("invalid json") return } value4 := gjson.Get(json, "name.last") fmt.Println(value4) // Decoding json string into map m, ok := gjson.Parse(json).Value().(map[string]interface{}) if !ok { // not a map fmt.Println("not map") } fmt.Println(m) // map[programmers:[map[firstName:Janet lastName:McLaughlin] map[firstName:Elliotte lastName:Hunter] map[firstName:Jason lastName:Harold]]] // Get multiple values at a time results := gjson.GetMany(json, "name.first", "name.last", "age") fmt.Println(results) // [Janet Prichard 47] }
4, Work in bytes
If your JSON is included in the [] byte slice, the GetBytes function exists. This is better than get (string (data, path)
var json []byte = ... result := gjson.GetBytes(json, path)
If you are using the gjson.GetBytes(json, path) function and want to avoid converting result.Raw to [] bytes, you can use the following pattern:
var json []byte = ... result := gjson.GetBytes(json, path) var raw []byte if result.Index > 0 { raw = json[result.Index:result.Index+len(result.Raw)] } else { raw = []byte(result.Raw) }
performance
Performance test of GJSON and encoding/json,ffjson,EasyJSON, jsonparser and JSON iterator
BenchmarkGJSONGet-8 3000000 372 ns/op 0 B/op 0 allocs/op BenchmarkGJSONUnmarshalMap-8 900000 4154 ns/op 1920 B/op 26 allocs/op BenchmarkJSONUnmarshalMap-8 600000 9019 ns/op 3048 B/op 69 allocs/op BenchmarkJSONDecoder-8 300000 14120 ns/op 4224 B/op 184 allocs/op BenchmarkFFJSONLexer-8 1500000 3111 ns/op 896 B/op 8 allocs/op BenchmarkEasyJSONLexer-8 3000000 887 ns/op 613 B/op 6 allocs/op BenchmarkJSONParserGet-8 3000000 499 ns/op 21 B/op 0 allocs/op BenchmarkJSONIterator-8 3000000 812 ns/op 544 B/op 9 allocs/op
JSON data is used as follows
{ "widget": { "debug": "on", "window": { "title": "Sample Konfabulator Widget", "name": "main_window", "width": 500, "height": 500 }, "image": { "src": "Images/Sun.png", "hOffset": 250, "vOffset": 250, "alignment": "center" }, "text": { "data": "Click Here", "size": 36, "style": "bold", "vOffset": 100, "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } } }
Each operation rotates through one of the following search paths:
widget.window.name widget.image.hOffset widget.text.onMouseUp
These benchmarks are based on the MacBook Pro 15 "2.8 GHz Intel Core i7 and go version 1.8
This article is translated from GJSON's Readme document. Each Demo has been tested. If you have any questions, please contact us