Go中使用gjson来操作JSON数据的实现


Posted in Golang onAugust 14, 2022

项目地址:https://github.com/tidwall/gjson

下载:

$ 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", "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"

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

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类型, 总是返回正传入路径个数的数量.

到此这篇关于Go中使用gjson来操作JSON数据的实现的文章就介绍到这了,更多相关Go gjson操作JSON内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Golang 相关文章推荐
Go各时间字符串使用解析
Apr 02 Golang
golang正则之命名分组方式
Apr 25 Golang
golang 接口嵌套实现复用的操作
Apr 29 Golang
Go语言 go程释放操作(退出/销毁)
Apr 30 Golang
解决golang post文件时Content-Type出现的问题
May 02 Golang
Golang 编译成DLL文件的操作
May 06 Golang
再次探讨go实现无限 buffer 的 channel方法
Jun 13 Golang
Go语言应该什么情况使用指针
Jul 25 Golang
一文搞懂Golang 时间和日期相关函数
Dec 06 Golang
Golang 字符串的常见操作
Apr 19 Golang
Golang bufio详细讲解
Apr 21 Golang
Go语言入门exec的基本使用
May 20 Golang
Go gorilla/sessions库安装使用
Aug 14 #Golang
Go gorilla securecookie库的安装使用详解
Aug 14 #Golang
go goth封装第三方认证库示例详解
Aug 14 #Golang
基于Python实现西西成语接龙小助手
Aug 05 #Golang
Python测试框架pytest核心库pluggy详解
Aug 05 #Golang
Go结合Gin导出Mysql数据到Excel表格
Aug 05 #Golang
GO中sync包自由控制并发示例详解
Aug 05 #Golang
You might like
深入解析PHP中逗号与点号的区别
2013/08/05 PHP
让CodeIgniter的ellipsize()支持中文截断的方法
2014/06/12 PHP
如何使用纯PHP实现定时器任务(Timer)
2015/07/31 PHP
JS分割字符串并放入数组的函数
2011/07/04 Javascript
jquery批量设置属性readonly和disabled的方法
2014/01/24 Javascript
超级简单的jquery操作表格方法
2014/12/15 Javascript
漫谈JS引擎的运行机制 你应该知道什么
2016/06/15 Javascript
JS HTML5实现拖拽移动列表效果
2020/08/27 Javascript
JavaScript实现类似拉勾网的鼠标移入移出效果
2016/10/27 Javascript
js实现3D图片展示效果
2017/03/09 Javascript
React中的refs的使用教程
2018/02/13 Javascript
js tab栏切换代码实例解析
2019/09/03 Javascript
vue 动态添加的路由页面刷新时失效的原因及解决方案
2021/02/26 Vue.js
[01:22:28]DOTA2-DPC中国联赛 正赛 SAG vs RNG BO3 第一场 1月18日
2021/03/11 DOTA
如何用Python和JS实现的Web SSH工具
2021/02/23 Python
css3背景图片透明叠加属性cross-fade简介及用法实例
2013/01/08 HTML / CSS
从零实现一个自定义html5播放器的示例代码
2017/08/01 HTML / CSS
全球知名旅游社区法国站点:TripAdvisor法国
2016/08/03 全球购物
德国隐形眼镜店:LuckyLens
2018/07/29 全球购物
Wiggle新西兰:自行车、跑步、游泳
2020/05/06 全球购物
俄罗斯连接商品和买家的在线平台:goods.ru
2020/11/30 全球购物
什么是命名空间(NameSpace)
2015/11/24 面试题
思想汇报范文
2013/11/04 职场文书
公关关系专员的自我评价分享
2013/11/20 职场文书
大学校庆邀请函
2014/01/11 职场文书
中秋节超市促销方案
2014/01/30 职场文书
小学生获奖感言范文
2014/02/02 职场文书
法人代表授权委托书
2014/04/08 职场文书
保险公司反洗钱宣传活动总结
2015/05/08 职场文书
2015年教导处教学工作总结
2015/07/22 职场文书
校园安全学习心得体会
2016/01/18 职场文书
2016年教师师德师风承诺书
2016/03/25 职场文书
MySQL中IF()、IFNULL()、NULLIF()、ISNULL()函数的使用详解
2021/06/26 MySQL
Spring实现内置监听器
2021/07/09 Java/Android
2022新作动画《福星小子》释出宣传影片 加入内田真礼&宫野真守配音演出
2022/04/08 日漫
Java字符缓冲流BufferedWriter
2022/04/09 Java/Android