Project Icon

gjson

高性能Go语言JSON解析工具

GJSON是一款高性能的Go语言JSON解析工具。它采用简洁的API设计,支持点表示法路径、数据迭代和JSON Lines处理等特性。GJSON在保持高速解析的同时,还具备出色的内存效率,适合处理大规模JSON数据。该库能够轻松完成从基础值提取到复杂查询等多种JSON操作任务,为Go开发者提供了强大而灵活的JSON处理方案。

GJSON
GoDoc GJSON Playground GJSON Syntax

快速获取JSON值

GJSON是一个Go语言包,提供了一种快速简单的方法来获取JSON文档中的值。它具有诸如一行检索、点号路径语法、迭代和解析JSON行等特性。

另外还可以查看用于修改JSON的SJSON,以及命令行工具JJ

本README是GJSON使用的快速概述,更多信息请查看GJSON语法

GJSON也可用于PythonRust

入门

安装

要开始使用GJSON,请安装Go并运行go get

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

这将检索该库。

获取值

Get函数在JSON中搜索指定路径。路径使用点号语法,例如"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用于处理JSON字节切片。

路径语法

以下是路径语法的快速概述,更完整的信息请查看GJSON语法

路径是由点分隔的一系列键。 键可以包含特殊通配符字符'*'和'?'。 要访问数组值,请使用索引作为键。 要获取数组中的元素数量或访问子路径,请使用'#'字符。 点和通配符字符可以用''转义。

{
  "name": {"first": "Tom", "last": "Anderson"},
  "age":37,
  "children": ["Sara","Alex","Jack"],
  "fav.movie": "Deer Hunter",
  "friends": [
    {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
    {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
    {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
  ]
}
"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"
friends.#(first!%"D*").last        >> "Craig"
friends.#(nets.#(=="fb"))#.first   >> ["Dale","Roger"]

请注意,在v1.3.0之前,查询使用#[...]括号。这在v1.3.0中被更改,以避免与新的多路径语法混淆。为了向后兼容,#[...]将继续工作,直到下一个主要版本。

结果类型

GJSON支持JSON类型stringnumberboolnull。 数组和对象以原始JSON类型返回。

Result类型包含以下之一:

bool,用于JSON布尔值
float64,用于JSON数字
string,用于JSON字符串字面量
nil,用于JSON null

要直接访问值:

result.Type           // 可以是String、Number、True、False、Null或JSON
result.Str            // 存储字符串
result.Num            // 存储float64数字
result.Raw            // 存储原始json
result.Index          // 原始值在原始json中的索引,零表示索引未知
result.Indexes        // 匹配包含'#'查询字符的路径上所有元素的索引

有多种适用于结果的便捷函数:

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类型之一:

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

result.Array() 函数返回一个值数组。如果结果表示不存在的值,则返回空数组。如果结果不是JSON数组,返回值将是包含一个结果的数组。

64位整数

result.Int()result.Uint() 调用能够读取全部64位,允许处理大型JSON整数。

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

修饰符和路径链接

1.2版本新增了对修饰符函数和路径链接的支持。

修饰符是对json执行自定义处理的路径组件。

多个路径可以使用管道字符"链接"在一起。这对于从修改后的查询中获取结果很有用。

例如,在上述json文档上使用内置的 @reverse 修饰符,我们将获取 children 数组并反转顺序:

"children|@reverse"           >> ["Jack","Alex","Sara"]
"children|@reverse|0"         >> "Jack"

目前有以下内置修饰符:

  • @reverse: 反转数组或对象的成员。
  • @ugly: 从json文档中删除所有空白。
  • @pretty: 使json文档更易读。
  • @this: 返回当前元素。可用于检索根元素。
  • @valid: 确保json文档有效。
  • @flatten: 扁平化数组。
  • @join: 将多个对象合并为单个对象。
  • @keys: 返回对象的键数组。
  • @values: 返回对象的值数组。
  • @tostr: 将json转换为字符串。包装json字符串。
  • @fromstr: 将字符串从json转换。解包json字符串。
  • @group: 对对象数组进行分组。参见 e4fc67c
  • @dig: 无需提供完整路径即可搜索值。参见 e8e87f2

修饰符参数

修饰符可以接受可选参数。参数可以是有效的JSON文档或仅字符。

例如,@pretty 修饰符将json对象作为其参数。

@pretty:{"sortKeys":true} 

这会使json更美观并对其所有键进行排序。

{
  "age":37,
  "children": ["Sara","Alex","Jack"],
  "fav.movie": "Deer Hunter",
  "friends": [
    {"age": 44, "first": "Dale", "last": "Murphy"},
    {"age": 68, "first": "Roger", "last": "Craig"},
    {"age": 47, "first": "Jane", "last": "Murphy"}
  ],
  "name": {"first": "Tom", "last": "Anderson"}
}

@pretty 的完整选项列表包括 sortKeysindentprefixwidth。 更多信息请参见 Pretty Options

自定义修饰符

您也可以添加自定义修饰符。

例如,这里我们创建一个修饰符,将整个json文档转换为大写或小写。

gjson.AddModifier("case", func(json, arg string) string {
  if arg == "upper" {
    return strings.ToUpper(json)
  }
  if arg == "lower" {
    return strings.ToLower(json)
  }
  return json
})
"children|@case:upper"           >> ["SARA","ALEX","JACK"]
"children|@case:lower|@reverse"  >> ["jack","alex","sara"]

JSON Lines

使用 .. 前缀支持 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
})

获取嵌套数组值

假设你想从以下json中获取所有的姓氏:

{
  "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())  // 打印 "Elliotte"

遍历对象或数组

ForEach 函数允许快速遍历对象或数组。 对于对象,键和值会被传递给迭代器函数。 对于数组,只传递值。 从迭代器返回 false 将停止迭代。

result := gjson.Get(json, "programmers")
result.ForEach(func(key, value gjson.Result) bool {
	println(value.String()) 
	return true // 继续迭代
})

简单解析和获取

有一个 Parse(json) 函数可以进行简单解析,以及 result.Get(path) 可以搜索结果。

例如,以下所有操作都会返回相同的结果:

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

检查值是否存在

有时你只想知道某个值是否存在。

value := gjson.Get(json, "name.last")
if !value.Exists() {
	println("没有姓氏")
} else {
	println(value.String())
}

// 或者一步完成
if gjson.Get(json, "name.last").Exists() {
	println("有姓氏")
}

验证 JSON

Get*Parse* 函数假定 json 格式良好。格式错误的 json 不会引发 panic,但可能返回意外结果。

如果你正在处理来自不可预测来源的 JSON,那么你可能想在使用 GJSON 之前进行验证。

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

解析到 map

要解析到 map[string]interface{}:

m, ok := gjson.Parse(json).Value().(map[string]interface{})
if !ok {
	// 不是 map
}

处理字节

如果你的 JSON 包含在 []byte 切片中,可以使用 GetBytes 函数。这比 Get(string(data), path) 更可取。

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

这是一种尽最大努力不分配原始 json 子切片的方法。这种方法利用了 result.Index 字段,它是原始 json 中原始数据的位置。result.Index 的值可能等于零,在这种情况下,result.Raw 会被转换为 []byte

性能

GJSON 与 encoding/jsonffjsonEasyJSONjsonparserjson-iterator 的基准测试对比

BenchmarkGJSONGet-16                11644512       311 ns/op       0 B/op	       0 allocs/op
BenchmarkGJSONUnmarshalMap-16        1122678      3094 ns/op    1920 B/op	      26 allocs/op
BenchmarkJSONUnmarshalMap-16          516681      6810 ns/op    2944 B/op	      69 allocs/op
BenchmarkJSONUnmarshalStruct-16       697053      5400 ns/op     928 B/op	      13 allocs/op
BenchmarkJSONDecoder-16               330450     10217 ns/op    3845 B/op	     160 allocs/op
BenchmarkFFJSONLexer-16              1424979      2585 ns/op     880 B/op	       8 allocs/op
BenchmarkEasyJSONLexer-16            3000000       729 ns/op     501 B/op	       5 allocs/op
BenchmarkJSONParserGet-16            3000000       366 ns/op      21 B/op	       0 allocs/op
BenchmarkJSONIterator-16             3000000       869 ns/op     693 B/op	      14 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 16" 2.4 GHz Intel Core i9 上使用 Go 1.17 运行的,可以在这里找到。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

稿定AI

稿定设计 是一个多功能的在线设计和创意平台,提供广泛的设计工具和资源,以满足不同用户的需求。从专业的图形设计师到普通用户,无论是进行图片处理、智能抠图、H5页面制作还是视频剪辑,稿定设计都能提供简单、高效的解决方案。该平台以其用户友好的界面和强大的功能集合,帮助用户轻松实现创意设计。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号