The official JSON library only supports serialization and deserialization of the whole. Like libraries in other languages, the JSON library supports operations such as a single getvalue/setvalue.
Find the next Golang related to the open source JSON library, Gjson star number is good, support the query function is very rich. But no interface is written. I didn't find a lap.
Find the JSON library with write capability. Only the definition type serialization or map serialization can be thought of. The following is the text, translated from the Project Readme:
Begin
Before you start using Gjson, install go and then run go get
:
$ go get -u github.com/tidwall/gjson
Get value
The Get query specifies the path through which .
to differentiate. such as "Name.last" or "age". If a matching path is found, the result is returned.
package mainimport "github.com/tidwall/gjson"const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`func main() { value := gjson.Get(json, "name.last") println(value.String())}
Output Result:
Prichard
At the same time, there are GetMany methods to get the value in bulk, and the GetBytes method gets the byte slice.
Path resolution
The path is a series .
of separated key concatenation.
The path may contain a wildcard ' * ' and '? '.
The array value is accessed by subscript.
Use ' # ' to get the value of the row in the element or to access the subpath.
.
and wildcard characters can be escaped by ' \ '.
{ "name": {"first": "Tom", "last": "Anderson"}, "age":37, "children": ["Sara","Alex","Jack"], "fav.movie": "Deer Hunter", "friends": [ {"first": "Dale", "last": "Murphy", "age": 44}, {"first": "Roger", "last": "Craig", "age": 68}, {"first": "Jane", "last": "Murphy", "age": 47} ]}
"name.last" >> "Anderson""age" >> 37"children" >> ["Sara","Alex","Jack"]"children.#" >> 3"children.1" >> "Alex""child*.2" >> "Jack""c?ildren.0" >> "Sara""fav\.movie" >> "Deer Hunter""friends.#.first" >> ["Dale","Roger","Jane"]"friends.1.last" >> "Craig"
You can also #[...]
query the array for the first matching item, or through the ' #[...] # ' query for all matching items.
Query support,,,, ==
!=
<
<=
>
>=
comparison operators and '% ' fuzzy matches.
friends.#[last=="Murphy"].first >> "Dale"friends.#[last=="Murphy"]#.first >> ["Dale","Jane"]friends.#[age>45]#.last >> ["Craig","Murphy"]friends.#[first%"D*"].last >> "Murphy"
JSON rows
Also supports JSON Lines, using ..
prefixes to treat multiple lines of document as Count groups.
Like what:
{"name": "Gilbert", "age": 61}{"name": "Alexa", "age": 34}{"name": "May", "age": 57}{"name": "Deloise", "age": 44}
..# >> 4..1 >> {"name": "Alexa", "age": 34}..3 >> {"name": "Deloise", "age": 44}..#.name >> ["Gilbert","Alexa","May","Deloise"]..#[name="May"].age >> 57
ForEachLines
method to iterate over the JSON.
gjson.ForEachLine(json, func(line gjson.Result) bool{ println(line.String()) return true})
Result Type
Gjson supports JSON types including,, string
number
, and bool
null
. Arrays and objects are blocked by the underlying type returned.
Result
One of the following types is held:
bool, for JSON booleansfloat64, for JSON numbersstring, for JSON string literalsnil, for JSON null
Direct access to value:
result.Type // can be String, Number, True, False, Null, or JSONresult.Str // holds the stringresult.Num // holds the float64 numberresult.Raw // holds the raw jsonresult.Index // index of raw value in original json, zero means index unknown
There are a variety of handy functions to get the results:
result.Exists() boolresult.Value() interface{}result.Int() int64result.Uint() uint64result.Float() float64result.String() stringresult.Bool() boolresult.Time() time.Timeresult.Array() []gjson.Resultresult.Map() map[string]gjson.Resultresult.Get(path string) Resultresult.ForEach(iterator func(key, value Result) bool)result.Less(token Result, caseSensitive bool) bool
result.Value()
method returns interface{}
one of the go basic types.
result.Array()
method returns a set of values.
If the result is a value that does not exist, an empty array will be returned.
If the result is not a JSON array, an array containing only one value will be returned.
boolean >> boolnumber >> float64string >> stringnull >> nilarray >> []interface{}object >> map[string]interface{}
64-bit integers
result.Int()
And result.Uint()
The return is a 64-bit large number.
result.Int() int64 // -9223372036854775808 to 9223372036854775807result.Uint() int64 // 0 to 18446744073709551615
Read nested arrays
If you want to get all the LastName from the following JSON:
{ "programmers": [ { "firstName": "Janet", "lastName": "McLaughlin", }, { "firstName": "Elliotte", "lastName": "Hunter", }, { "firstName": "Jason", "lastName": "Harold", } ]}
You can use the following path programmers.#.lastName
:
result := gjson.Get(json, "programmers.#.lastName")for _, name := range result.Array() { println(name.String())}
You can also get the objects in the array:
name := gjson.Get(json, `programmers.#[lastName="Hunter"].firstName`)println(name.String()) // prints "Elliotte"
Object or array iteration
ForEach
method allows you to quickly iterate over an object or an array.
Key and value are passed to the object's iterator function.
Only value is passed to the array. An iterator return false
will terminate the iteration.
Simple Parse and get
Parse(json)
The method can simply parse the JSON and result.Get(path)
query the result.
For example, the following scenarios will return the same result:
gjson.Parse(json).Get("name").Get("last")gjson.Get(json, "name").Get("last")gjson.Get(json, "name.last")
Checks if value exists
Sometimes you want to know if a value exists.
value := gjson.Get(json, "name.last")if !value.Exists() { println("no last name")} else { println(value.String())}// Or as one stepif gjson.Get(json, "name.last").Exists() { println("has a last name")}
Validating JSON
Get*
And Parse*
method expected JSON format is normal, if not normal, will return unexpected results.
If the JSON source you read is unpredictable, then you can verify this beforehand by Gjson.
if !gjson.Valid(json) { return errors.New("invalid json")}value := gjson.Get(json, "name.last")
Deserialize to map
Deserialization to map[string]interface{}
:
m, ok := gjson.Parse(json).Value().(map[string]interface{})if !ok { // not a map}## 处理Bytes如果你的JSON包含字节数组切片, 与其调用`Get(string(data), path)`, 不如调用[GetBytes](https://godoc.org/github.com/tidwall/gjson#GetBytes)方法更优.```govar json []byte = ...result := gjson.GetBytes(json, path)
If you are using the gjson.GetBytes(json, path)
method and you want to avoid result.Raw
switching from to []byte
, you can use this mode:
var json []byte = ...result := gjson.GetBytes(json, path)var raw []byteif result.Index > 0 { raw = json[result.Index:result.Index+len(result.Raw)]} else { raw = []byte(result.Raw)}
This is the best mode and does not reallocate memory for sub-slices. This mode uses a result.Index
field that points directly to the location in the original JSON where raw data is located.
If result.Raw
it is converted []byte
, it result.Index
will be 0.
Get multiple values at once
GetMany
Method can be used to fetch multiple values at the same time.
results := gjson.GetMany(json, "name.first", "name.last", "age")
The return value is a []Result
type that always returns the number of positive incoming paths.
Performance
Tested the Gjson and the Encoding/json,
Ffjson,
Easyjson,
Jsonparser,
and Json-iterator
BenchmarkGJSONGet-8 3000000 372 ns/op 0 B/op 0 allocs/opBenchmarkGJSONUnmarshalMap-8 900000 4154 ns/op 1920 B/op 26 allocs/opBenchmarkJSONUnmarshalMap-8 600000 9019 ns/op 3048 B/op 69 allocs/opBenchmarkJSONDecoder-8 300000 14120 ns/op 4224 B/op 184 allocs/opBenchmarkFFJSONLexer-8 1500000 3111 ns/op 896 B/op 8 allocs/opBenchmarkEasyJSONLexer-8 3000000 887 ns/op 613 B/op 6 allocs/opBenchmarkJSONParserGet-8 3000000 499 ns/op 21 B/op 0 allocs/opBenchmarkJSONIterator-8 3000000 812 ns/op 544 B/op 9 allocs/op
JSON used:
{ "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 is rotated in the following search path:
widget.window.namewidget.image.hOffsetwidget.text.onMouseUp
These benchmarks are run on the MacBook Pro "2.8 GHz Intel Core i7, which you can find using go 1.8. Here.