微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

golang gjson json库简介

目录

安装

获取值

路径解析

JSON 行

Result Type

64-bit integers

读取嵌套数组

对象或数组迭代

简易的Parse和Get

检查value是否存在

验证JSON

反序列化到map

一次获取多个值

性能


官方的json库,只支持整体的序列化与反序列化. 像其它语言的库,json库都支持单个getValue/setValue这类操作.
找了下golang相关的开源json库,GJSON star数不错,支持查询功能很丰富. 但是没有写入接口. 找了一圈也没有
写入功能
的json库. 能想到的只有定义类型序列化或map序列化了. 以下是正文,翻译自项目readme:

安装

开始使用GJSON之前,先安装Go,然后运行go get:

$ go get -u github.com/tidwall/gjson

获取

Get查询指定路径,通过.来区分. 比如"name.last"或者"age". 如果找到了匹配路径,将返回结果.

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

同时有 GetMany 方法批量获取值,也有 GetBytes 方法获取字节切片.

路径解析

路径是一系列被.分隔的key拼接而成.
路径可能包含通配符'*'和'?'.
通过下标访问数组值.
通过'#'来获取值在元素中的排位或访问子路径.
.通配符可以通过'\'来转义.

{
  "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","age": 47}
  ]
}
"name.last"          >> "Anderson"
"age"                >> 37
"children"           >> ["Sara","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"

你同样能通过#[...]查询数组中的第一个匹配的项,或通过'#[...]#'查询所有匹配的项.
查询支持==,!=,<,<=,>,>=比较运算符和'%'模糊匹配.

friends.#[last=="Murphy"].first    >> "Dale"
friends.#[last=="Murphy"]#.first   >> ["Dale","Jane"]
friends.#[age>45]#.last            >> ["Craig","Murphy"]
friends.#[first%"D*"].last         >> "Murphy"

JSON 行

同样支持JSON Lines,使用 .. 前缀,把多行文档视作数组.

比如:

{"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 方法可以迭代json.

gjson.ForEachLine(json,func(line gjson.Result) bool{
    println(line.String())
    return true
})

Result Type

GJSON支持json类型包括 string,number,bool,and null. 数组和对象被挡住基础类型返回.

Result 持有如下其中一种类型:

bool,for JSON booleans
float64,for JSON numbers
string,for JSON string literals
nil,for JSON null

直接访问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

有各种各样的方便的函数可以获取结果:

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

result.Value() 方法返回 interface{} Go基本类型之一.

result.Array() 方法返回一组值.
如果结果是不存在的值,将会返回空数组.
如果结果不是JSON数组,将会返回只包含一个值的数组.

boolean >> bool
number  >> float64
string  >> string
null    >> nil
array   >> []interface{}
object  >> map[string]interface{}

64-bit integers

result.Int()result.Uint() 返回的是64位大数字.

result.Int() int64    // -9223372036854775808 to 9223372036854775807
result.Uint() int64   // 0 to 18446744073709551615

读取嵌套数组

假如你想从下列json获取所有的lastName:

{
  "programmers": [
    {
      "firstName": "Janet","lastName": "McLaughlin",},{
      "firstName": "Elliotte","lastName": "Hunter",{
      "firstName": "Jason","lastName": "Harold",}
  ]
}

你可以使用如下路径programmers.#.lastName:

result := gjson.Get(json,"programmers.#.lastName")
for _,name := range result.Array() {
    println(name.String())
}

你同样能获取数组里的对象:

name := gjson.Get(json,`programmers.#[lastName="Hunter"].firstName`)
println(name.String())  // prints "Elliotte"

对象或数组迭代

ForEach方法允许你快速的迭代对象或数组.
key和value被传递给对象的迭代器函数.
只有value被传递给数组. 迭代器返回false将会终止迭代.

简易的Parse和Get

Parse(json)方法可以简单的分析json,result.Get(path)查询结果.

比如,下面的几种情况都将返回相同的结果:

gjson.Parse(json).Get("name").Get("last")
gjson.Get(json,"name").Get("last")
gjson.Get(json,"name.last")

检查value是否存在

有时你想要知道值是否存在.

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")
}

验证JSON

Get*Parse* 方法预期json格式是正常的,如果不正常,将会返回不可预料的结果.

如果你读取的json来源不可预料,那么你可以通过GJSON这么事先验证.

if !gjson.Valid(json) {
    return errors.New("invalid json")
}
value := gjson.Get(json,"name.last")

反序列化到map

反序列化到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)方法更优.
```go
var json []byte = ...
result := gjson.GetBytes(json,path)

如果你在使用gjson.GetBytes(json,path)方法,并且你想避免从result.Raw 转换到 []byte,你可以使用这种模式:

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)
}

这是最好的模式,不会为子切片重新分配内存. 这个模式使用了result.Index字段,它直接指向了raw data所处原来json中的位置.
如果result.Raw是转换成[]byte的,result.Index将会为0.

一次获取多个值

GetMany方法可以用于同时获取多个值.

results := gjson.GetMany(json,"name.first","name.last","age")

返回值是[]Result类型,总是返回正传入路径个数的数量.

性能

测试了GJSON以及 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:

{
  "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;"
    }
  }
}    

每个操作都是在以下的搜索路径中进行旋转的:

widget.window.name
widget.image.hOffset
widget.text.onmouseup

这些基准是在MacBook Pro 15" 2.8 GHz英特尔酷睿i7上运行的,使用Go 1.8,可以找到. here.


 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐