golang支持JSONPath的抽象JSON处理插件库ajson的使用
Golang 支持 JSONPath 的抽象 JSON 处理插件库 ajson 的使用
Abstract JSON (ajson) 是一个小型 Golang 包,提供了对 JSON 的解析器,并支持 JSONPath,适用于不确定 JSON 结构的情况。
基本功能
Unmarshal
方法会扫描整个字节切片来创建 JSON 结构的根节点Marshal
方法会将当前Node
对象序列化为 JSON 结构- 每个
Node
都有自己的类型和计算值(按需计算) JSONPath
方法会根据 JSONPath 请求返回当前 JSON 数据中找到的元素切片
安装
import "github.com/spyzhov/ajson"
基本使用示例
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
json := []byte(`...`) // 你的JSON数据
// 解析JSON
root, _ := ajson.Unmarshal(json)
// 使用JSONPath查找所有price节点
nodes, _ := root.JSONPath("$..price")
// 修改每个price节点的值并添加currency字段
for _, node := range nodes {
node.SetNumeric(node.MustNumeric() * 1.25)
node.Parent().AppendObject("currency", ajson.StringNode("", "EUR"))
}
// 将修改后的JSON序列化
result, _ := ajson.Marshal(root)
fmt.Printf("%s", result)
}
JSONPath 支持
ajson 支持 JSONPath 选择器,语法参考 http://goessner.net/articles/JsonPath/
JSONPath 语法元素
JSONPath | 描述 |
---|---|
$ |
根对象/元素 |
@ |
当前对象/元素 |
. 或 [] |
子操作符 |
.. |
递归下降(从 E4X 借鉴) |
* |
通配符(所有对象/元素不论名称) |
[] |
下标操作符 |
[,] |
联合操作符(XPath 中用于合并节点集) |
[start:end:step] |
数组切片操作符(从 ES4 借鉴) |
?() |
应用过滤(脚本)表达式 |
() |
脚本表达式,使用底层脚本引擎 |
高级功能示例
1. 使用 true
在路径中
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
json := []byte(`{"foo": [true, null, false, 1, "bar", true, 1e3], "bar": [true, "baz", false]}`)
// 查找所有值为true的节点
result, _ := ajson.JSONPath(json, `$..[?(@ == true)]`)
fmt.Printf("Count of `true` values: %d", len(result))
// 输出: Count of `true` values: 3
}
2. 使用 avg
函数计算数组平均值
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
json := []byte(`{"prices": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}`)
// 解析JSON
root, err := ajson.Unmarshal(json)
if err != nil {
panic(err)
}
// 使用avg函数计算平均值
result, err := ajson.Eval(root, `avg($.prices)`)
if err != nil {
panic(err)
}
fmt.Printf("Avg price: %0.1f", result.MustNumeric())
// 输出: Avg price: 5.5
}
3. 使用正则表达式匹配
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
json := []byte(`[{"name":"Foo","mail":"foo@example.com"},{"name":"bar","mail":"bar@example.org"}]`)
// 使用正则匹配邮件地址
result, err := ajson.JSONPath(json, `$.[?(@.mail =~ '.+@example\\.com')]`)
if err != nil {
panic(err)
}
fmt.Printf("JSON: %s", result[0].Source())
// 输出: JSON: {"name":"Foo","mail":"foo@example.com"}
}
复杂JSON处理示例
计算平均价格
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
},
"tools": null
}
}
使用 Unmarshal 处理
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
data := []byte(`{"store": {"book": [
{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95},
{"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99},
{"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99},
{"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99}],
"bicycle": {"color": "red", "price": 19.95}, "tools": null}}`)
root, err := ajson.Unmarshal(data)
if err != nil {
panic(err)
}
store := root.MustKey("store").MustObject()
var prices float64
size := 0
for _, objects := range store {
if objects.IsArray() && objects.Size() > 0 {
size += objects.Size()
for _, object := range objects.MustArray() {
prices += object.MustKey("price").MustNumeric()
}
} else if objects.IsObject() && objects.HasKey("price") {
size++
prices += objects.MustKey("price").MustNumeric()
}
}
if size > 0 {
fmt.Println("AVG price:", prices/float64(size))
} else {
fmt.Println("AVG price:", 0)
}
}
使用 JSONPath 处理
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
data := []byte(`{"store": {"book": [
{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95},
{"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99},
{"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99},
{"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99}],
"bicycle": {"color": "red", "price": 19.95}, "tools": null}}`)
// 使用JSONPath查找所有price节点
nodes, err := ajson.JSONPath(data, "$..price")
if err != nil {
panic(err)
}
var prices float64
size := len(nodes)
for _, node := range nodes {
prices += node.MustNumeric()
}
if size > 0 {
fmt.Println("AVG price:", prices/float64(size))
} else {
fmt.Println("AVG price:", 0)
}
}
使用 Eval 计算平均值
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
json := []byte(`{"store": {"book": [
{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95},
{"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99},
{"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99},
{"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99}],
"bicycle": {"color": "red", "price": 19.95}, "tools": null}}`)
root, err := ajson.Unmarshal(json)
if err != nil {
panic(err)
}
// 使用eval计算平均值
result, err := ajson.Eval(root, "avg($..price)")
if err != nil {
panic(err)
}
fmt.Println("AVG price:", result.MustNumeric())
}
修改并重新序列化JSON
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
json := []byte(`{"store": {"book": [
{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95},
{"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99},
{"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99},
{"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99}],
"bicycle": {"color": "red", "price": 19.95}, "tools": null}}`)
root := ajson.Must(ajson.Unmarshal(json))
result := ajson.Must(ajson.Eval(root, "avg($..price)"))
// 添加平均价格到JSON
err := root.AppendObject("price(avg)", result)
if err != nil {
panic(err)
}
// 序列化修改后的JSON
marshalled, err := ajson.Marshal(root)
if err != nil {
panic(err)
}
fmt.Printf("%s", marshalled)
}
命令行工具
你可以从发布页面下载 ajson
CLI,或者从源代码安装:
go get github.com/spyzhov/ajson/cmd/ajson@v0.9.6
使用示例:
ajson "avg($..registered.age)" "https://randomuser.me/api/?results=5000"
ajson "$.results.*.name" "https://randomuser.me/api/?results=10"
curl -s "https://randomuser.me/api/?results=10" | ajson "$..coordinates"
ajson "$" example.json
echo "3" | ajson "2 * pi * $"
docker logs image-name -f | ajson -qm 'root($[?(@=="ERROR" && key(@)=="severity")])'
性能
ajson 的性能与 encoding/json
包相当。基准测试结果示例:
$ go test -bench=. -cpu=1 -benchmem
goos: linux
goarch: amd64
pkg: github.com/spyzhov/ajson
BenchmarkUnmarshal_AJSON 121656 10060 ns/op 5712 B/op 118 allocs/op
BenchmarkUnmarshal_JSON 102674 11381 ns/op 960 B/op 32 allocs/op
BenchmarkJSONPath_all_prices 63314 16385 ns/op 7496 B/op 178 allocs/op
许可证
MIT 许可证。详见 LICENSE 文件。
更多关于golang支持JSONPath的抽象JSON处理插件库ajson的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang支持JSONPath的抽象JSON处理插件库ajson的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用 ajson 库处理 JSONPath 查询
ajson 是一个 Go 语言实现的 JSONPath 处理库,它提供了类似 JavaScript 中操作 JSON 的灵活方式。下面我将介绍如何使用 ajson 库进行 JSONPath 查询和处理。
安装 ajson
go get github.com/spyzhov/ajson
基本用法
1. 解析 JSON 数据
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
// 原始 JSON 数据
jsonData := `{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}`
// 解析 JSON
root, err := ajson.Unmarshal([]byte(jsonData))
if err != nil {
panic(err)
}
}
2. 使用 JSONPath 查询
// 查询所有书籍的作者
authors, err := root.JSONPath("$.store.book[*].author")
if err != nil {
panic(err)
}
for _, author := range authors {
fmt.Println("Author:", author.String())
}
// 查询价格低于10的书籍
cheapBooks, err := root.JSONPath("$.store.book[?(@.price < 10)]")
if err != nil {
panic(err)
}
for _, book := range cheapBooks {
title, _ := book.GetKey("title").String()
price, _ := book.GetKey("price").Numeric()
fmt.Printf("Cheap book: %s (%.2f)\n", title, price)
}
// 查询自行车颜色
color, err := root.JSONPath("$.store.bicycle.color")
if err != nil {
panic(err)
}
fmt.Println("Bicycle color:", color[0].String())
3. 修改 JSON 数据
// 修改自行车价格
bicyclePrice, err := root.JSONPath("$.store.bicycle.price")
if err != nil {
panic(err)
}
err = bicyclePrice[0].SetNumeric(15.99)
if err != nil {
panic(err)
}
// 添加新书
books, err := root.JSONPath("$.store.book")
if err != nil {
panic(err)
}
newBook := map[string]interface{}{
"category": "fantasy",
"author": "J.R.R. Tolkien",
"title": "The Lord of the Rings",
"price": 22.99,
}
err = books[0].AppendObject(newBook)
if err != nil {
panic(err)
}
// 获取修改后的 JSON
modifiedJSON, err := ajson.Marshal(root)
if err != nil {
panic(err)
}
fmt.Println(string(modifiedJSON))
高级功能
1. 使用过滤器
// 查找特定类别的书籍
fantasyBooks, err := root.JSONPath("$.store.book[?(@.category == 'fantasy')]")
if err != nil {
panic(err)
}
for _, book := range fantasyBooks {
title, _ := book.GetKey("title").String()
fmt.Println("Fantasy book:", title)
}
2. 处理嵌套结构
// 获取所有价格
allPrices, err := root.JSONPath("$..price")
if err != nil {
panic(err)
}
for _, price := range allPrices {
p, _ := price.Numeric()
fmt.Println("Price:", p)
}
3. 动态构建 JSON
// 创建新的 JSON 结构
newRoot := ajson.New()
storeNode := ajson.NewObject()
bookArray := ajson.NewArray()
book1 := ajson.NewObject()
book1.MustSetKey("title", ajson.StringNode("", "New Book 1"))
book1.MustSetKey("price", ajson.NumericNode("", 9.99))
book2 := ajson.NewObject()
book2.MustSetKey("title", ajson.StringNode("", "New Book 2"))
book2.MustSetKey("price", ajson.NumericNode("", 14.99))
bookArray.MustAppend(book1)
bookArray.MustAppend(book2)
storeNode.MustSetKey("book", bookArray)
newRoot.MustSetKey("store", storeNode)
newJSON, err := ajson.Marshal(newRoot)
if err != nil {
panic(err)
}
fmt.Println(string(newJSON))
注意事项
- ajson 使用标准的 JSONPath 语法,但有一些扩展功能
- 错误处理很重要,特别是在处理动态 JSON 结构时
- 对于大型 JSON 文档,考虑性能影响
- ajson 支持大多数 JSONPath 操作符,包括递归下降(
..
)、通配符(*
)等
ajson 库提供了强大而灵活的方式来处理 JSON 数据,特别适合需要复杂查询和修改的场景。相比标准库的 encoding/json,它更适合需要 JSONPath 功能的应用程序。