golang的GJSON库
2019独角兽企业重金招聘Python工程师标准>>>
get json values quickly
GJSON is a Go package that provides a fast and simple way to get values from a json document. It has features such as one line retrieval, dot notation paths, iteration, and parsing json lines.
Also check out SJSON for modifying json, and the JJ command line tool.
Getting Started
Installing
To start using GJSON, install Go and run go get
:
$ go get -u github.com/tidwall/gjson
This will retrieve the library.
Get a value
Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". When the value is found it's returned immediately.
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()) }
This will print:
Prichard
There's also the GetMany function to get multiple values at once, and GetBytes for working with JSON byte slices.
Path Syntax
A path is a series of keys separated by a dot. A key may contain special wildcard characters '*' and '?'. To access an array value use the index as the key. To get the number of elements in an array or to access a child path, use the '#' character. The dot and wildcard characters can be escaped with '\'.
{"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 an array for the first match by using #[...]
, or find all matches with #[...]#
. Queries support the ==
, !=
, <
, <=
, >
, >=
comparison operators and the simple pattern matching %
operator.
friends.#[last=="Murphy"].first >> "Dale"
friends.#[last=="Murphy"]#.first >> ["Dale","Jane"]
friends.#[age>45]#.last >> ["Craig","Murphy"]
friends.#[first%"D*"].last >> "Murphy"
JSON Lines
There's support for JSON Lines using the ..
prefix, which treats a multilined document as an array.
For example:
{"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
The ForEachLines
function will iterate through JSON lines.
gjson.ForEachLine(json, func(line gjson.Result) bool{println(line.String())return true })
Result Type
GJSON supports the json types string
, number
, bool
, and null
. Arrays and Objects are returned as their raw json types.
The Result
type holds one of these:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON string literals
nil, for JSON null
To directly access the value:
result.Type // can be String, Number, True, False, Null, or JSON result.Str // holds the string result.Num // holds the float64 number result.Raw // holds the raw json result.Index // index of raw value in original json, zero means index unknown
There are a variety of handy functions that work on a result:
result.Exists() bool result.Value() interface{} result.Int() int64 result.Uint() uint64 result.Float() float64 result.String() string result.Bool() bool result.Time() time.Time result.Array() []gjson.Result result.Map() map[string]gjson.Result result.Get(path string) Result result.ForEach(iterator func(key, value Result) bool) result.Less(token Result, caseSensitive bool) bool
The result.Value()
function returns an interface{}
which requires type assertion and is one of the following Go types:
The result.Array()
function returns back an array of values. If the result represents a non-existent value, then an empty array will be returned. If the result is not a JSON array, the return value will be an array containing one result.
boolean >> bool number >> float64 string >> string null >> nil array >> []interface{} object >> map[string]interface{}
64-bit integers
The result.Int()
and result.Uint()
calls are capable of reading all 64 bits, allowing for large JSON integers.
result.Int() int64 // -9223372036854775808 to 9223372036854775807 result.Uint() int64 // 0 to 18446744073709551615
Get nested array values
Suppose you want all the last names from the following json:
{"programmers": [{"firstName": "Janet", "lastName": "McLaughlin", }, {"firstName": "Elliotte", "lastName": "Hunter", }, {"firstName": "Jason", "lastName": "Harold", }] }
You would use the path "programmers.#.lastName" like such:
result := gjson.Get(json, "programmers.#.lastName") for _, name := range result.Array() {println(name.String()) }
You can also query an object inside an array:
name := gjson.Get(json, `programmers.#[lastName="Hunter"].firstName`) println(name.String()) // prints "Elliotte"
Iterate through an object or array
The ForEach
function allows for quickly iterating through an object or array. The key and value are passed to the iterator function for objects. Only the value is passed for arrays. Returning false
from an iterator will stop iteration.
result := gjson.Get(json, "programmers") result.ForEach(func(key, value gjson.Result) bool {println(value.String()) return true // keep iterating })
Simple Parse and Get
There's a Parse(json)
function that will do a simple parse, and result.Get(path)
that will search a result.
For example, all of these will return the same result:
gjson.Parse(json).Get("name").Get("last") gjson.Get(json, "name").Get("last") gjson.Get(json, "name.last")
Check for the existence of a value
Sometimes you just 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 step if gjson.Get(json, "name.last").Exists() {println("has a last name") }
Validate JSON
The Get*
and Parse*
functions expects that the json is well-formed. Bad json will not panic, but it may return back unexpected results.
If you are consuming JSON from an unpredictable source then you may want to validate prior to using GJSON.
if !gjson.Valid(json) {return errors.New("invalid json") } value := gjson.Get(json, "name.last")
Unmarshal to a map
To unmarshal to a map[string]interface{}
:
m, ok := gjson.Parse(json).Value().(map[string]interface{}) if !ok {// not a map }
Working with Bytes
If your JSON is contained in a []byte
slice, there's the GetBytes function. This is preferred over Get(string(data), path)
.
var json []byte = ... result := gjson.GetBytes(json, path)
If you are using the gjson.GetBytes(json, path)
function and you want to avoid converting result.Raw
to a []byte
, then you can use this 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) }
This is a best-effort no allocation sub slice of the original json. This method utilizes the result.Index
field, which is the position of the raw data in the original json. It's possible that the value of result.Index
equals zero, in which case the result.Raw
is converted to a []byte
.
Get multiple values at once
The GetMany
function can be used to get multiple values at the same time.
results := gjson.GetMany(json, "name.first", "name.last", "age")
The return value is a []Result
, which will always contain exactly the same number of items as the input paths.
Performance
Benchmarks of GJSON alongside 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 document 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 was rotated though one of the following search paths:
widget.window.name
widget.image.hOffset
widget.text.onMouseUp
These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.8 and can be be found here.
Contact
Josh Baker @tidwall
License
GJSON source code is available under the MIT License.
转载于:https://my.oschina.net/u/3553591/blog/1625530
golang的GJSON库相关推荐
- 再测Golang的JSON库
2019独角兽企业重金招聘Python工程师标准>>> 写项目一直需要进行序列化,听到了,也看到了很多同学老师对各个golang的json库进行测评.那本人为什么还要继续进行这一次测 ...
- Golang实现requests库
Golang实现requests库 简单的封装下,方便使用,像python的requests库一样. Github地址 Github 支持 GET.POST.PUT.DELETE applicatio ...
- go语言调用c 的头文件 so,Golang生成共享库(shared library)以及Golang生成C可调用的动态库.so和静态库.a...
Golang类似于C的静态语言,效率也接近于C,如果Golang也可以导出可供C调用的库,那可以和很多高级语言say goodbye了,goodbye似乎又有点武断,但至少说,Golang可以做很多事 ...
- 用 Golang 实现矩阵运算库
用 Golang 实现矩阵运算库 天下文章一大抄 抄过来的 转载的 别来沾边
- GoLang之标准库net/http包源码
GoLang之标准库net/http包源码 目录 GoLang之标准库net/http包源码 1.net/http包介绍 2.http.ListenAndServe函数 3.http.Handle函数 ...
- Golang高性能日志库zap + lumberjack 日志切割组件详解
文章篇幅较长,可以先收藏防止迷路~ 目录 zap日志库 1. why zap? 2. 简单使用 3. 自定义logger例子 4. Gin项目使用zap 6. lumberjack 日志切割组件 za ...
- Golang的viper库
Golang的viper库 1.作用 viper 是一个配置解决方案,拥有丰富的特性: 支持 JSON/TOML/YAML/HCL/envfile/Java properties 等多种格式的配置文件 ...
- golang桌面gui库fyne使用
golang桌面gui库fyne使用 使用 初始项目 新建项目文件夹fyna 执行go mod init 执行go get fyne.io/fyne/v2 执行go mod tidy 创建main.g ...
- GoLang之标准库strings包
文章目录 GoLang之标准库strings包 1.函数介绍 2.EqualFold 3.TrimSpace 4.HasPrefix 5.HasSuffix 6.Index 7.LastIndex 8 ...
最新文章
- 安装envi出现cannot find lincese_Ubuntu 16.04 安装 CUDA10.1 (解决循环登陆的问题)
- 【算法与数据结构】在n个数中取第k大的数(基础篇)
- SAP 电商云 Spartacus UI 的 CORS 设置
- cloudfoundry_在Cloudfoundry上部署RESTful服务
- 图深度学习-第2部分
- 【leetcode】ZigZag Conversion
- redis的java客户端名称_java里常用的redis客户端简介
- 敏捷开发系列学习总结(15)——Spotify敏捷模式详解三部曲第三篇:工程文化
- Gradle_04_解决多项目同级依赖时找不到符号的异常
- [译] 第二天:AngularJS - 认识AngularJS
- 强大的Mockito测试框架
- EIGRP中AD与FD的区别
- 微信公众号分销商城(源码+数据库+文档)
- 通信原理中的erf/erfc函数
- FreeCAD源码分析: PartDesign模块
- 微信小程序跳转公众号图文内容
- GPU显存占满但利用率却很低
- OBCA认证知识点-part3
- Accuracy, Precision, Recall和F1-score解释
- 做PPT浪费时间,那是因为你不知道这四个工具