golang高性能JSON解析与JSONPath操作插件库OjG的使用

Golang高性能JSON解析与JSONPath操作插件库OjG的使用

OjG (Optimized JSON for Go) 是一个高性能的JSON解析器,提供多种JSON处理工具。OjG特别适合处理大型数据集,尤其是数据结构不固定的情况。

主要特性

  • 快速的JSON解析器(性能优于标准库)
  • 完整的JSONPath实现,支持简单类型和结构体操作
  • 通用类型(虽然不是Go泛型,但提供类型安全的JSON元素)
  • 快速的JSON验证器(比io.Reader快7倍)
  • 带排序选项的快速JSON写入器(快4倍)
  • 使用简单组装计划从JSON源构建JSON
  • 使用push和pop方法的简单数据构建器
  • 类似Ruby Oj的对象编码和解码方法
  • 简单编码表示法(SEN),一种省略逗号和引号的懒JSON写法

使用示例

基本解析

package main

import (
	"fmt"
	"github.com/ohler55/ojg/oj"
)

func main() {
	// 解析JSON字符串
	obj, err := oj.ParseString(`{
		"a":[
			{"x":1,"y":2,"z":3},
			{"x":2,"y":4,"z":6}
		]
	}`)
	if err != nil {
		fmt.Println("解析错误:", err)
		return
	}
	fmt.Println("解析结果:", obj)
}

使用JSONPath表达式

package main

import (
	"fmt"
	"github.com/ohler55/ojg/jp"
	"github.com/ohler55/ojg/oj"
)

func main() {
	// 解析JSON字符串
	obj, _ := oj.ParseString(`{
		"a":[
			{"x":1,"y":2,"z":3},
			{"x":2,"y":4,"z":6}
		]
	}`)

	// 解析JSONPath表达式
	x, err := jp.ParseString("a[?(@.x > 1)].y")
	if err != nil {
		fmt.Println("JSONPath解析错误:", err)
		return
	}
	
	// 应用JSONPath获取结果
	ys := x.Get(obj)
	fmt.Println("JSONPath结果:", ys) // 输出: [4]
}

命令行工具

OjG提供了一个命令行工具oj,可以使用JSONPath进行过滤和提取JSON元素,还支持排序、重新格式化和着色选项。

$ oj -m "(@.name == 'Pete')" myfile.json

安装

go get github.com/ohler55/ojg
go get github.com/ohler55/ojg/cmd/oj

或者在Go文件中直接导入:

import (
	"github.com/ohler55/ojg/alt"
	"github.com/ohler55/ojg/asm"
	"github.com/ohler55/ojg/gen"
	"github.com/ohler55/ojg/jp"
	"github.com/ohler55/ojg/oj"
	"github.com/ohler55/ojg/sen"
)

要构建并安装oj应用程序:

go install ./...

或者使用Homebrew安装:

brew install oj

性能基准

OjG在性能上显著优于标准库的JSON处理:

Parse string/[]byte
       json.Unmarshal           55916 ns/op    17776 B/op    334 allocs/op
         oj.Parse               39570 ns/op    18488 B/op    429 allocs/op
   oj-reuse.Parse               17881 ns/op     5691 B/op    364 allocs/op

   oj-reuse.Parse        █████████████████████▉ 3.13
         oj.Parse        █████████▉ 1.41
       json.Unmarshal    ▓▓▓▓▓▓▓ 1.00

Parse io.Reader
       json.Decode              63029 ns/op    32449 B/op    344 allocs/op
         oj.ParseReader         34289 ns/op    22583 B/op    430 allocs/op
   oj-reuse.ParseReader         25094 ns/op     9788 B/op    365 allocs/op
         oj.TokenizeLoad        13610 ns/op     6072 B/op    157 allocs/op

         oj.TokenizeLoad ████████████████████████████████▍ 4.63
   oj-reuse.ParseReader  █████████████████▌ 2.51
         oj.ParseReader  ████████████▊ 1.84
       json.Decode       ▓▓▓▓▓▓▓ 1.00

to JSON with indentation
       json.Marshal             78762 ns/op    26978 B/op    352 allocs/op
         oj.JSON                 7662 ns/op        0 B/op      0 allocs/op
        sen.Bytes                9053 ns/op        0 B/op      0 allocs/op

         oj.JSON         ███████████████████████████████████████████████████████████████████████▉ 10.28
        sen.Bytes        ████████████████████████████████████████████████████████████▉ 8.70
       json.Marshal      ▓▓▓▓▓▓▓ 1.00

更多关于golang高性能JSON解析与JSONPath操作插件库OjG的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang高性能JSON解析与JSONPath操作插件库OjG的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用OjG进行高性能JSON解析与JSONPath操作

OjG是Go语言中一个高性能的JSON处理库,提供了快速的JSON解析和JSONPath查询功能。下面我将详细介绍如何使用OjG进行高效的JSON操作。

安装OjG

首先安装OjG库:

go get github.com/ohler55/ojg/oj
go get github.com/ohler55/ojg/jp

基本JSON解析

快速解析JSON字符串

package main

import (
	"fmt"
	"github.com/ohler55/ojg/oj"
)

func main() {
	jsonStr := `{"name":"John","age":30,"city":"New York"}`

	// 解析JSON
	obj, err := oj.ParseString(jsonStr)
	if err != nil {
		panic(err)
	}

	// 转换为map
	data := obj.(map[string]interface{})
	fmt.Println("Name:", data["name"])
	fmt.Println("Age:", data["age"])
	fmt.Println("City:", data["city"])
}

带选项的解析

func parseWithOptions() {
	jsonStr := `{"name":"John","age":30,"city":"New York"}`

	// 创建解析选项
	opt := &oj.Options{
		UseFloat:    true,   // 使用float64而不是默认的int
		TimeFormat:  "unix", // 时间格式
		CreateKey:   "^",    // 特殊字符处理
		FullTyping:  true,   // 保留完整类型信息
	}

	obj, err := oj.ParseString(jsonStr, opt)
	if err != nil {
		panic(err)
	}
	
	fmt.Printf("%#v\n", obj)
}

JSONPath查询

OjG提供了强大的JSONPath功能来查询JSON数据。

基本JSONPath查询

package main

import (
	"fmt"
	"github.com/ohler55/ojg/jp"
	"github.com/ohler55/ojg/oj"
)

func main() {
	jsonStr := `{
		"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
	obj, err := oj.ParseString(jsonStr)
	if err != nil {
		panic(err)
	}

	// 创建JSONPath表达式
	x, err := jp.ParseString("$.store.book[*].author")
	if err != nil {
		panic(err)
	}

	// 执行查询
	authors := x.Get(obj)
	fmt.Println("Authors:", authors)
}

常用JSONPath示例

func jsonPathExamples() {
	jsonStr := `{"store": {"book": [{"title": "Book1"}, {"title": "Book2"}]}}`
	obj, _ := oj.ParseString(jsonStr)

	// 1. 获取所有书籍标题
	x1, _ := jp.ParseString("$.store.book[*].title")
	titles := x1.Get(obj)
	fmt.Println("Titles:", titles)

	// 2. 获取第一本书
	x2, _ := jp.ParseString("$.store.book[0]")
	firstBook := x2.Get(obj)
	fmt.Println("First book:", firstBook)

	// 3. 获取最后一本书
	x3, _ := jp.ParseString("$.store.book[-1]")
	lastBook := x3.Get(obj)
	fmt.Println("Last book:", lastBook)

	// 4. 条件查询
	x4, _ := jp.ParseString("$.store.book[?(@.title == 'Book2')]")
	matchingBooks := x4.Get(obj)
	fmt.Println("Matching books:", matchingBooks)
}

性能优化技巧

  1. 重用解析器:避免重复创建解析器实例
var parser = oj.Parser{Reuse: true}

func parseWithReuse(jsonStr string) {
	obj, err := parser.ParseString(jsonStr)
	if err != nil {
		panic(err)
	}
	// 使用obj...
}
  1. 预编译JSONPath:对于频繁使用的JSONPath表达式,提前编译
var (
	bookTitlesPath, _ = jp.ParseString("$.store.book[*].title")
	bookPricesPath, _ = jp.ParseString("$.store.book[*].price")
)

func queryPrecompiledPaths(obj interface{}) {
	titles := bookTitlesPath.Get(obj)
	prices := bookPricesPath.Get(obj)
	// 使用结果...
}
  1. 使用简单类型:在可能的情况下使用简单类型而非interface{}
type Book struct {
	Title  string  `json:"title"`
	Author string  `json:"author"`
	Price  float64 `json:"price"`
}

type Store struct {
	Books []Book `json:"book"`
}

func parseToStruct(jsonStr string) {
	var data struct {
		Store Store `json:"store"`
	}
	
	err := oj.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		panic(err)
	}
	
	// 直接访问结构体字段,类型安全且高效
	for _, book := range data.Store.Books {
		fmt.Println(book.Title, book.Price)
	}
}

高级功能

修改JSON数据

func modifyJson() {
	jsonStr := `{"name":"John","age":30}`
	obj, _ := oj.ParseString(jsonStr)

	// 创建修改表达式
	x, _ := jp.ParseString("$.age")
	
	// 修改age字段
	x.Set(obj, 31)
	
	// 转换为JSON字符串
	modifiedJson, _ := oj.Marshal(obj)
	fmt.Println(string(modifiedJson))
}

流式解析大JSON

对于大JSON文件,可以使用流式解析:

func streamParse() {
	jsonStr := `{"results":[{"id":1},{"id":2},{"id":3}]}`
	
	// 创建流解析器
	callback := func(obj interface{}) bool {
		fmt.Println("Got object:", obj)
		return true // 返回false可以停止解析
	}
	
	err := oj.Parse([]byte(jsonStr), callback)
	if err != nil {
		panic(err)
	}
}

性能对比

OjG在性能上通常优于标准库的encoding/json,特别是在处理大JSON数据时:

  1. 解析速度通常快2-5倍
  2. 内存使用更高效
  3. JSONPath查询比手动遍历map更简洁高效

结论

OjG是Go中处理JSON的高性能选择,特别适合:

  • 需要快速解析大JSON文件的场景
  • 需要复杂JSON查询的场景
  • 对性能有较高要求的应用

通过合理使用OjG的解析选项、JSONPath预编译和流式处理,可以显著提升JSON处理的效率。

回到顶部