leptjson

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 16, 2025 License: MIT Imports: 7 Imported by: 0

README

从零开始的 JSON 库教程(十二):JSON Path 实现

JSON Path 简介

JSON Path 是一种用于从 JSON 文档中提取数据的查询语言,类似于 XML 的 XPath。它提供了一种简洁的语法来指定 JSON 结构中的位置,便于从复杂的嵌套 JSON 数据中查找、提取和操作数据。

JSON Path 的核心思想是通过路径表达式来定位 JSON 文档中的元素。Stefan Goessner 在 2007 年首次提出了这个概念,尽管目前尚未有官方标准,但已被广泛采用。

JSON Path 语法

JSON Path 使用以下基本语法元素:

  1. $ - 根对象/元素
  2. @ - 当前对象/元素
  3. . - 子元素操作符
  4. [] - 下标操作符
  5. .. - 递归下降
  6. * - 通配符,表示所有对象/元素
  7. ?() - 过滤表达式
  8. () - 脚本表达式
  9. , - 并集操作
示例

假设有如下 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
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

常见的 JSON Path 表达式示例:

JSON Path 描述
$.store.book[*].author 所有书籍的作者
$..author 所有作者,无论在哪个层级
$.store.* store 对象的所有成员
$.store..price store 下所有价格
$..book[2] 第三本书
$..book[-1:] 最后一本书
$..book[0,1] 前两本书
$..book[:2] 前两本书(使用切片语法)
$..book[?(@.price<10)] 所有价格小于 10 的书
$..book[?(@.category=="fiction")] 所有分类为 "fiction" 的书

本章实现功能

在本章中,我们实现了一个 JSON Path 解析器和求值器,支持以下功能:

  1. 路径解析:将 JSON Path 表达式解析为令牌序列
  2. 属性访问:支持点表示法 .property 和括号表示法 ['property']
  3. 数组索引:支持通过索引访问数组元素,包括负索引
  4. 数组切片:支持类似 Python 的切片语法 [start:end:step]
  5. 通配符:支持 * 通配符,匹配所有属性或数组元素
  6. 递归下降:支持 .. 操作符,在任意深度查找匹配的元素
  7. 多种查询方法:提供单值查询和多值查询功能

实现细节

主要数据结构
  1. JSONPath: 表示解析后的 JSON Path 表达式

    type JSONPath struct {
        Path   string  // 原始路径表达式
        Tokens []Token // 解析后的令牌列表
    }
    
  2. Token: 表示 JSON Path 中的一个令牌

    type Token struct {
        Type  TokenType // 令牌类型
        Value string    // 令牌值
    }
    
  3. TokenType: 令牌类型枚举

    type TokenType int
    
    const (
        ROOT TokenType = iota
        CURRENT
        DOT
        // ... 其他类型
    )
    
  4. SliceInfo: 用于数组切片操作

    type SliceInfo struct {
        Start int
        End   int
        Step  int
    }
    
解析过程

JSON Path 解析分为以下步骤:

  1. 验证路径表达式的基本有效性
  2. 从左到右遍历路径表达式,识别并创建令牌
  3. 处理特殊情况,如属性名、数组索引、切片等
  4. 生成令牌序列,表示路径表达式的结构
求值过程

对于给定的 JSON 文档和 JSON Path 表达式,求值过程是:

  1. 从根节点开始,按照令牌序列依次求值
  2. 对于每种令牌类型,应用相应的操作(属性访问、数组索引等)
  3. 递归处理复杂操作,如通配符和递归下降
  4. 收集满足条件的所有值,返回结果集

使用示例

基本用法
// 创建 JSON 文档
doc := &Value{}
// ... 填充文档数据 ...

// 方法 1: 使用 NewJSONPath 创建 JSONPath 对象
path, err := NewJSONPath("$.store.book[0].title")
if err != nil {
    // 处理错误
}
results, err := path.Query(doc)
if err != nil {
    // 处理错误
}

// 方法 2: 使用便捷函数
results, err := QueryString(doc, "$.store.book[0].title")
if err != nil {
    // 处理错误
}

// 获取单个结果
result, err := QueryOneString(doc, "$.store.book[0].title")
if err != nil {
    // 处理错误
}
title := GetString(result) // 使用相应的获取器获取具体值
复杂查询示例
// 获取所有书籍作者
authors, _ := QueryString(doc, "$.store.book[*].author")

// 找出所有价格(无论位置)
prices, _ := QueryString(doc, "$..price")

// 使用数组切片获取第一本到第二本书
firstTwoBooks, _ := QueryString(doc, "$.store.book[0:2]")

// 反向获取所有书籍
reversedBooks, _ := QueryString(doc, "$.store.book[::-1]")

支持的特性和限制

已支持的特性
  • 基本路径导航($, ., [])
  • 属性访问(.property 和 ['property'])
  • 数组索引访问,包括负索引
  • 数组切片操作,支持起始、结束和步长
  • 通配符(*)匹配
  • 递归下降(..)操作
  • 友好的错误消息
当前限制
  • 不支持过滤表达式 ?()
  • 不支持脚本表达式 ()
  • 不支持联合操作符 [expr1,expr2,expr3]
  • 不支持当前节点引用 @
未来扩展计划
  • 实现过滤表达式支持
  • 添加并集操作支持
  • 优化性能,特别是对于大型 JSON 文档
  • 添加更多错误恢复机制

参考资料

Documentation

Overview

cycle_detection.go - 循环引用检测实现

json_path.go - JSON Path 实现

json_pointer.go - JSON指针实现 (RFC6901)

json_schema.go - JSON Schema 验证实现(基于部分 JSON Schema Draft 7)

leptjson.go - Go语言版JSON库

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildJSONPointer

func BuildJSONPointer(segments ...interface{}) (string, error)

BuildJSONPointer 创建一个JSON指针字符串

func ClearArray

func ClearArray(v *Value)

ClearArray 清空数组的所有元素

func ClearObject

func ClearObject(v *Value)

ClearObject 清空对象的所有成员

func Copy

func Copy(dst, src *Value)

Copy 深度复制一个JSON值

func CopySafe

func CopySafe(dst, src *Value) error

CopySafe 安全复制JSON值,避免循环引用

func CopySafeWithReplacement

func CopySafeWithReplacement(dst, src *Value)

CopySafeWithReplacement 带替换的安全复制

func CustomCopySafeWithReplacement

func CustomCopySafeWithReplacement(dst, src *Value, replacer CircularReplacer)

CustomCopySafeWithReplacement 使用自定义替换器的安全复制

func Equal

func Equal(lhs, rhs *Value) bool

Equal 判断两个JSON值是否相等

func EraseArrayElement

func EraseArrayElement(v *Value, index, count int)

EraseArrayElement 删除数组中从index开始的count个元素

func FindObjectIndex

func FindObjectIndex(v *Value, key string) int

FindObjectIndex 查找JSON对象中指定键的索引

func Free

func Free(v *Value)

Free 释放JSON值占用的资源

func GetArrayCapacity

func GetArrayCapacity(v *Value) int

GetArrayCapacity 获取数组当前的容量

func GetArraySize

func GetArraySize(v *Value) int

GetArraySize 获取JSON数组的大小

func GetBoolean

func GetBoolean(v *Value) bool

GetBoolean 获取JSON布尔值

func GetErrorMessage

func GetErrorMessage(code ParseError) string

GetErrorMessage 根据错误码获取错误消息

func GetNumber

func GetNumber(v *Value) float64

GetNumber 获取JSON数字值

func GetObjectCapacity

func GetObjectCapacity(v *Value) int

GetObjectCapacity 获取对象的容量

func GetObjectKey

func GetObjectKey(v *Value, index int) string

GetObjectKey 获取JSON对象的键

func GetObjectSize

func GetObjectSize(v *Value) int

GetObjectSize 获取JSON对象的大小

func GetString

func GetString(v *Value) string

GetString 获取JSON字符串值

func HasCycle

func HasCycle(v *Value) bool

HasCycle 检测JSON值中是否存在循环引用

func Move

func Move(dst, src *Value)

Move 将源值移动到目标值,并将源值设为null

func ParseJSONPointer

func ParseJSONPointer(pointer string) (*JSONPointer, JSONPointerError)

ParseJSONPointer 解析JSON指针字符串 例如: "/foo/0/bar" => ["foo", "0", "bar"]

func PopBackArrayElement

func PopBackArrayElement(v *Value)

PopBackArrayElement 移除数组末尾的元素

func RemoveObjectValue

func RemoveObjectValue(v *Value, index int)

RemoveObjectValue 移除对象中指定索引的成员

func RemoveValueByPointer

func RemoveValueByPointer(v *Value, pointerStr string) error

RemoveValueByPointer 使用JSON指针删除值

func ReserveArray

func ReserveArray(v *Value, capacity int)

ReserveArray 扩充数组容量

func ReserveObject

func ReserveObject(v *Value, capacity int)

ReserveObject 扩充对象容量

func SafeCopyWithReplacer

func SafeCopyWithReplacer(dst, src *Value, replacer CircularReplacer)

SafeCopyWithReplacer 带替换器的安全复制,处理循环引用

func SetArray

func SetArray(v *Value, capacity int)

SetArray 设置值为数组类型,可以预分配容量

func SetBoolean

func SetBoolean(v *Value, b bool)

SetBoolean 设置JSON布尔值

func SetNull

func SetNull(v *Value)

SetNull 将值设置为NULL类型

func SetNumber

func SetNumber(v *Value, n float64)

SetNumber 设置JSON数字值

func SetObject

func SetObject(v *Value)

SetObject 设置值为对象类型,可以预分配容量

func SetString

func SetString(v *Value, s string)

SetString 设置JSON字符串值

func SetValueByPointer

func SetValueByPointer(v *Value, pointerStr string, value *Value) error

SetValueByPointer 使用JSON指针设置值

func ShrinkArray

func ShrinkArray(v *Value)

ShrinkArray 缩小数组容量至实际大小

func ShrinkObject

func ShrinkObject(v *Value)

ShrinkObject 缩小对象容量至实际大小

func Swap

func Swap(lhs, rhs *Value)

Swap 交换两个JSON值

Types

type CircularReplacer

type CircularReplacer func(path []string) *Value

CircularReplacer 定义了在发现循环引用时的替换函数类型

type CycleError

type CycleError int

CycleError 表示循环引用错误

const (
	CYCLE_OK CycleError = iota
	CYCLE_DETECTED
)

循环引用错误常量

func DetectCycle

func DetectCycle(v *Value) CycleError

DetectCycle 检测JSON值中是否存在循环引用

func SafeCopy

func SafeCopy(dst, src *Value) CycleError

SafeCopy 安全复制JSON值,检测并处理循环引用

func (CycleError) Error

func (e CycleError) Error() string

实现 Error 接口

type EnhancedError

type EnhancedError struct {
	Code          ParseError // 错误码
	Message       string     // 错误消息
	Line          int        // 行号
	Column        int        // 列号
	Context       string     // 错误发生的上下文
	Pointer       string     // 错误位置指针(比如 "----^")
	SourceInput   string     // 输入源
	IsRecoverable bool       // 是否可恢复
}

EnhancedError 定义了一个增强的错误类型,包含详细信息

func (*EnhancedError) Error

func (e *EnhancedError) Error() string

Error 实现error接口

type JSONPath

type JSONPath struct {
	Path   string  // 原始路径表达式
	Tokens []Token // 令牌列表
}

JSONPath 表示一个解析后的 JSON Path 表达式

func NewJSONPath

func NewJSONPath(path string) (*JSONPath, error)

NewJSONPath 解析 JSON Path 表达式并创建一个 JSONPath 对象

func (*JSONPath) Query

func (jp *JSONPath) Query(doc *Value) ([]*Value, error)

Query 使用 JSON Path 查询 JSON 值并返回匹配的值列表

func (*JSONPath) QueryOne

func (jp *JSONPath) QueryOne(doc *Value) (*Value, error)

QueryOne 返回第一个匹配的值,如果没有匹配则返回 nil

type JSONPathError

type JSONPathError struct {
	Path    string // JSON Path 表达式
	Message string // 错误消息
	Index   int    // 错误发生的位置
}

JSONPathError 表示解析或执行 JSON Path 时的错误

func (JSONPathError) Error

func (e JSONPathError) Error() string

Error 实现 error 接口

type JSONPointer

type JSONPointer struct {
	// contains filtered or unexported fields
}

JSONPointer 表示一个JSON指针(RFC6901)

func GetJSONPointer

func GetJSONPointer(segments ...interface{}) (*JSONPointer, error)

GetJSONPointer 创建一个指向指定路径的JSONPointer 例如: NewJSONPointer("foo", 0, "bar") => "/foo/0/bar"

func (*JSONPointer) Get

func (p *JSONPointer) Get(root *Value) (*Value, JSONPointerError)

Get 根据JSON指针获取值

func (*JSONPointer) Remove

func (p *JSONPointer) Remove(root *Value) JSONPointerError

Remove 根据JSON指针删除值

func (*JSONPointer) Set

func (p *JSONPointer) Set(root *Value, value *Value) JSONPointerError

Set 根据JSON指针设置值

func (*JSONPointer) String

func (p *JSONPointer) String() string

创建一个JSON指针字符串表示

type JSONPointerError

type JSONPointerError int

JSONPointerError 表示JSON指针相关错误

const (
	POINTER_OK JSONPointerError = iota
	POINTER_INVALID_FORMAT
	POINTER_INDEX_OUT_OF_RANGE
	POINTER_KEY_NOT_FOUND
	POINTER_INVALID_TARGET
)

JSON指针错误常量

func (JSONPointerError) Error

func (e JSONPointerError) Error() string

实现 Error 接口

type JSONSchema

type JSONSchema struct {
	Schema *Value // 存储 JSON Schema 的 Value 对象
}

JSONSchema 表示一个 JSON Schema 对象

func NewJSONSchema

func NewJSONSchema(schemaJSON string) (*JSONSchema, error)

NewJSONSchema 创建一个新的 JSON Schema

func NewJSONSchemaFromValue

func NewJSONSchemaFromValue(schema *Value) (*JSONSchema, error)

NewJSONSchemaFromValue 从 Value 对象创建 JSON Schema

func (*JSONSchema) Validate

func (js *JSONSchema) Validate(data *Value) *SchemaValidationResult

Validate 根据 Schema 验证 JSON 数据

type Member

type Member struct {
	K string // 键
	V *Value // 值
}

Member 表示对象的成员(键值对)

type ParseError

type ParseError int

ParseError 表示解析错误

const (
	PARSE_OK                           ParseError = iota // 解析成功
	PARSE_EXPECT_VALUE                                   // 期望一个值
	PARSE_INVALID_VALUE                                  // 无效的值
	PARSE_ROOT_NOT_SINGULAR                              // 根节点不唯一
	PARSE_NUMBER_TOO_BIG                                 // 数字太大
	PARSE_MISS_QUOTATION_MARK                            // 缺少引号
	PARSE_INVALID_STRING_ESCAPE                          // 无效的转义序列
	PARSE_INVALID_STRING_CHAR                            // 无效的字符
	PARSE_INVALID_UNICODE_HEX                            // 无效的Unicode十六进制
	PARSE_INVALID_UNICODE_SURROGATE                      // 无效的Unicode代理对
	PARSE_MISS_COMMA_OR_SQUARE_BRACKET                   // 缺少逗号或方括号
	PARSE_MISS_KEY                                       // 缺少键
	PARSE_MISS_COLON                                     // 缺少冒号
	PARSE_MISS_COMMA_OR_CURLY_BRACKET                    // 缺少逗号或花括号
	PARSE_MAX_DEPTH_EXCEEDED                             // 超过最大嵌套深度
	PARSE_COMMENT_NOT_CLOSED                             // 注释未闭合
)

解析错误常量

func Parse

func Parse(v *Value, json string) ParseError

Parse 解析JSON文本(使用默认选项)

func ParseWithOptions

func ParseWithOptions(v *Value, json string, options ParseOptions) ParseError

ParseWithOptions 使用自定义选项解析JSON文本

解析步骤: 1. 跳过前导空白字符 2. 解析JSON值 3. 跳过后续空白字符 4. 检查是否还有额外内容(这将导致PARSE_ROOT_NOT_SINGULAR错误)

func (ParseError) Error

func (e ParseError) Error() string

Error 返回解析错误的描述

type ParseOptions

type ParseOptions struct {
	MaxDepth          int  // 最大嵌套深度
	AllowComments     bool // 是否允许注释
	AllowTrailing     bool // 是否允许尾随逗号
	StrictMode        bool // 严格模式(更严格的检查)
	RecoverFromErrors bool // 是否从非致命错误恢复
}

ParseOptions 定义解析选项

func DefaultParseOptions

func DefaultParseOptions() ParseOptions

DefaultParseOptions 返回默认解析选项

type SchemaValidationError

type SchemaValidationError struct {
	Path    string // 导致错误的 JSON 路径
	Message string // 错误描述
}

SchemaValidationError 表示 JSON Schema 验证错误

func (SchemaValidationError) Error

func (e SchemaValidationError) Error() string

实现 Error 接口

type SchemaValidationResult

type SchemaValidationResult struct {
	Valid  bool                    // 是否验证通过
	Errors []SchemaValidationError // 验证错误列表
}

SchemaValidationResult 存储验证结果

func (*SchemaValidationResult) AddError

func (r *SchemaValidationResult) AddError(path, message string)

AddError 添加验证错误

type SliceInfo

type SliceInfo struct {
	Start int
	End   int
	Step  int
}

SliceInfo 存储数组切片信息

type StringifyError

type StringifyError int

StringifyError 表示字符串化错误

const (
	STRINGIFY_OK StringifyError = iota // 字符串化成功
)

字符串化错误常量

func Stringify

func Stringify(v *Value) (string, StringifyError)

Stringify 将Value转换为JSON字符串

func (StringifyError) Error

func (e StringifyError) Error() string

Error 返回字符串化错误的描述

type Token

type Token struct {
	Type  TokenType // 令牌类型
	Value string    // 令牌值
}

Token 表示 JSON Path 中的一个令牌

type TokenType

type TokenType int

TokenType 表示 JSON Path 令牌的类型

const (
	ROOT              TokenType = iota // $ - 根节点
	CURRENT                            // @ - 当前节点
	DOT                                // . - 子属性访问
	RECURSIVE_DESCENT                  // .. - 递归下降
	WILDCARD                           // * - 通配符
	BRACKET_START                      // [ - 下标访问开始
	BRACKET_END                        // ] - 下标访问结束
	INDEX                              // 数字索引
	PROPERTY                           // 属性名
	SLICE                              // 切片 [start:end:step]
	UNION                              // 并集 [expr,expr]
	FILTER                             // ?() - 过滤器
)

type Value

type Value struct {
	Type ValueType `json:"type"` // 值类型
	N    float64   `json:"n"`    // 数字值(当Type为NUMBER时有效)
	S    string    `json:"s"`    // 字符串值(当Type为STRING时有效)
	A    []*Value  `json:"a"`    // 数组值(当Type为ARRAY时有效)
	O    []Member  `json:"o"`    // 对象值(当Type为OBJECT时有效)
}

Value 表示一个JSON值

func DefaultCircularReplacer

func DefaultCircularReplacer(path []string) *Value

DefaultCircularReplacer 默认循环引用替换器

func FindObjectKey

func FindObjectKey(v *Value, key string) (*Value, bool)

FindObjectKey 根据键名在对象中查找对应值,如果找到返回值和true,否则返回nil和false

func GetArrayElement

func GetArrayElement(v *Value, index int) *Value

GetArrayElement 获取JSON数组的元素

func GetObjectValue

func GetObjectValue(v *Value, index int) *Value

GetObjectValue 获取JSON对象的值

func GetObjectValueByKey

func GetObjectValueByKey(v *Value, key string) *Value

GetObjectValueByKey 根据键获取JSON对象的值

func GetValueByPointer

func GetValueByPointer(v *Value, pointerStr string) (*Value, error)

GetValueByPointer 使用JSON指针获取值

func InsertArrayElement

func InsertArrayElement(v *Value, index int) *Value

InsertArrayElement 在指定位置插入元素,并返回该元素

func PushBackArrayElement

func PushBackArrayElement(v *Value) *Value

PushBackArrayElement 在数组末尾添加一个新元素,并返回该元素

func QueryOneString

func QueryOneString(doc *Value, path string) (*Value, error)

QueryOneString 是一个便捷函数,返回匹配路径的第一个值

func QueryString

func QueryString(doc *Value, path string) ([]*Value, error)

QueryString 是一个便捷函数,直接使用路径表达式查询 JSON 值

func SetObjectValue

func SetObjectValue(v *Value, key string) *Value

SetObjectValue 设置对象的键值对,如果键已存在则返回其值指针,否则添加新的键值对并返回新值指针

func (Value) String

func (v Value) String() string

String 返回Value的字符串表示

type ValueType

type ValueType int

ValueType 表示JSON值的类型

const (
	NULL ValueType = iota
	FALSE
	TRUE
	NUMBER
	STRING
	ARRAY
	OBJECT
)

JSON值类型常量

func GetType

func GetType(v *Value) ValueType

GetType 获取JSON值的类型

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL