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中semaphore(信号量)源码
Apr 03 Golang
基于go interface{}==nil 的几种坑及原理分析
Apr 24 Golang
Go语言 go程释放操作(退出/销毁)
Apr 30 Golang
对Golang中的FORM相关字段理解
May 02 Golang
Golang中异常处理机制详解
Jun 08 Golang
go web 预防跨站脚本的实现方式
Jun 11 Golang
Go语言读取txt文档的操作方法
Jan 22 Golang
victoriaMetrics库布隆过滤器初始化及使用详解
Apr 05 Golang
Golang数据类型和相互转换
Apr 12 Golang
golang使用map实现去除重复数组
Apr 14 Golang
Golang 实现WebSockets
Apr 24 Golang
GoFrame gredis缓存DoVar Conn连接对象 自动序列化GoFrame gredisDo/DoVar方法Conn连接对象自动序列化/反序列化总结
Jun 14 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
各种战术和打法的原创者
2020/03/04 星际争霸
PHP与已存在的Java应用程序集成
2006/10/09 PHP
六酷社区论坛HOME页清新格调免费版 下载
2007/03/07 PHP
php 404错误页面实现代码
2009/06/22 PHP
codeigniter教程之多文件上传使用示例
2014/02/11 PHP
php缓冲输出实例分析
2015/01/05 PHP
音乐播放用的的几个函数
2006/09/07 Javascript
Javascript学习笔记一 之 数据类型
2010/12/15 Javascript
JS实现时间格式化的方式汇总
2013/10/16 Javascript
JS实现两表格里数据来回转移的方法
2015/05/28 Javascript
解决Extjs下拉框不显示的问题
2017/06/21 Javascript
详解vue-cli中的ESlint配置文件eslintrc.js
2017/09/25 Javascript
解决vue组件中使用v-for出现告警问题及v for指令介绍
2017/11/11 Javascript
js实时监控文本框输入字数的实例代码
2018/01/18 Javascript
详解TypeScript+Vue 插件 vue-class-component的使用总结
2019/02/18 Javascript
vue跳转方式(打开新页面)及传参操作示例
2020/01/26 Javascript
js的Object.assign用法示例分析
2020/03/05 Javascript
[56:58]VP vs Optic 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python中数字以及算数运算符的相关使用
2015/10/12 Python
python下如何查询CS反恐精英的服务器信息
2017/01/17 Python
python 出现SyntaxError: non-keyword arg after keyword arg错误解决办法
2017/02/14 Python
python实现逻辑回归的方法示例
2017/05/02 Python
新手常见6种的python报错及解决方法
2018/03/09 Python
如何基于python操作json文件获取内容
2019/12/24 Python
Python Django搭建网站流程图解
2020/06/13 Python
python中watchdog文件监控与检测上传功能
2020/10/30 Python
高档奢华时装在线目的地:FORWARD by elyse walker
2017/10/16 全球购物
倩碧英国官网:Clinique英国
2018/08/10 全球购物
澳大利亚领先的在线药房:Pharmacy Online(有中文站)
2020/02/22 全球购物
财务副总经理工作职责
2013/11/25 职场文书
户外用品商店创业计划书
2014/01/29 职场文书
产品开发计划书
2014/04/27 职场文书
个人承诺书格式
2014/06/03 职场文书
2015年社区综治宣传月活动总结
2015/03/25 职场文书
酒店前台接待岗位职责
2015/04/02 职场文书
党员理论学习心得体会
2016/01/21 职场文书