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: 4 Imported by: 0

README

从零开始的 JSON 库教程(九):错误处理增强

高级教程开始

从本章开始,我们将进入 JSON 库的高级教程部分,着重于提升库的实用性、性能和安全性。在基础教程(教程一至八)中,我们已经实现了一个功能完整的 JSON 库,包括解析、生成和各种操作功能。现在,我们将进一步完善这个库,使其更加健壮和实用。

教程九:增强错误处理

在本教程中,我们将为JSON解析库添加增强的错误处理功能,提供更丰富的错误信息和更强大的恢复机制。这些功能对于构建健壮的应用程序至关重要,尤其是在处理用户输入或外部数据源时。

主要内容

  1. 详细的错误信息

    • 不仅显示错误类型,还提供行号和列号
    • 显示错误上下文(出错位置附近的代码)
    • 提供指向错误位置的指针,直观展示错误位置
  2. 错误恢复机制

    • 允许从某些错误中恢复并继续解析
    • 可配置的错误恢复策略
    • 在遇到非致命错误时用null替代错误值
  3. 解析选项

    • 支持JSON注释(单行//和多行/* */)
    • 可配置的嵌套深度限制
    • 错误恢复开关
  4. 改进的错误处理接口

    • 使用结构化的错误信息
    • 更好的位置跟踪
    • 支持国际化错误消息

实现要点

1. 增强的错误信息

我们实现了EnhancedError结构体,它包含以下信息:

  • 错误代码:指示错误的类型
  • 错误消息:人类可读的错误描述
  • 行号和列号:错误发生的位置
  • 上下文:错误发生附近的代码片段
  • 指针:指向错误位置的可视化指示器
  • 源码输入:原始JSON输入
  • 是否可恢复:指示该错误是否可以从中恢复
2. 解析上下文改进
  • 跟踪行号和列号
  • 记录每行的起始位置以便定位错误
  • 支持嵌套深度限制和检查
  • 增加了对注释解析的支持
3. 错误恢复策略

允许从某些非致命错误中恢复:

  • 数组中的无效值
  • 对象中的无效值
  • 格式错误的字符串
  • 其他可恢复的语法错误

使用示例

基本解析(与之前版本兼容):

var v Value
err := Parse(&v, jsonText)
if err != PARSE_OK {
    // 处理错误
}

使用增强选项:

var v Value
options := ParseOptions{
    RecoverFromErrors: true,  // 启用错误恢复
    AllowComments: true,      // 允许注释
    MaxDepth: 100             // 设置最大嵌套深度
}
err := ParseWithOptions(&v, jsonText, options)

性能考虑

虽然增强的错误处理提供了更多功能,但也带来了一些性能开销:

  • 跟踪位置信息需要额外的计算
  • 错误恢复需要额外的状态管理
  • 注释解析增加了额外的代码路径

在性能关键的应用中,可以通过配置选项来禁用某些高开销的功能。

结论

本教程通过增强错误处理系统,大大提高了JSON解析库的用户友好性和健壮性。这些改进使库更适合在生产环境中使用,特别是在处理不可信数据时。通过提供详细的错误信息和恢复机制,可以帮助开发者更快地定位和解决问题。

Tutorial 10 - 高级数据结构

本章实现了两个重要的高级数据结构功能:

  1. JSON 指针(JSON Pointer):基于 RFC 6901 标准实现,可以使用类似路径的语法访问和操作 JSON 文档中的特定部分。
  2. 循环引用检测与处理:检测和处理 JSON 数据中的循环引用问题,解决了深层复制和序列化时的潜在问题。

JSON 指针功能

JSON 指针是一种用于指向 JSON 文档特定部分的字符串语法。例如,指针字符串 /foo/0/bar 表示访问对象的 "foo" 键,然后访问数组的第一个元素,最后访问该元素的 "bar" 键。

主要特性
  • 完整支持 RFC 6901 标准
  • 支持转义字符:~0 表示 ~~1 表示 /
  • 提供获取、设置和删除值的操作
  • 支持对象属性和数组索引的访问
使用示例
// 解析 JSON 数据
doc := &leptjson.Value{}
leptjson.Parse(doc, `{"foo": {"bar": 42}, "baz": [0, 1, {"qux": "hello"}]}`)

// 使用 JSON 指针获取值
value, err := leptjson.GetValueByPointer(doc, "/foo/bar")
if err == nil {
    fmt.Println(leptjson.GetNumber(value)) // 输出: 42
}

// 使用 JSON 指针设置值
newValue := &leptjson.Value{}
leptjson.SetNumber(newValue, 100)
leptjson.SetValueByPointer(doc, "/foo/bar", newValue)

// 使用 JSON 指针删除值
leptjson.RemoveValueByPointer(doc, "/baz/0")

// 构建 JSON 指针字符串
pointerStr, _ := leptjson.BuildJSONPointer("foo", "bar")
// 结果: "/foo/bar"

循环引用检测与处理

循环引用是指 JSON 结构中存在环形引用关系的情况,这在标准 JSON 中是不允许的,但在内存中的表示可能会出现。

主要特性
  • 精确检测对象和数组中的循环引用
  • 安全复制功能,避免无限递归
  • 提供循环引用替换策略
  • 支持自定义替换器函数
使用示例
// 检测循环引用
if leptjson.HasCycle(doc) {
    fmt.Println("JSON 数据包含循环引用")
}

// 安全复制(会在发现循环引用时返回错误)
dst := &leptjson.Value{}
if err := leptjson.CopySafe(dst, doc); err != nil {
    fmt.Println("无法复制,因为存在循环引用")
}

// 使用默认替换器进行安全复制
dst := &leptjson.Value{}
leptjson.CopySafeWithReplacement(dst, doc)
// 循环引用会被替换为字符串 "循环引用 -> /path/to/cycle"

// 使用自定义替换器
customReplacer := func(path []string) *leptjson.Value {
    v := &leptjson.Value{}
    leptjson.SetObject(v)
    
    cycleType := leptjson.SetObjectValue(v, "type")
    leptjson.SetString(cycleType, "cycle")
    
    cyclePath := leptjson.SetObjectValue(v, "path")
    leptjson.SetString(cyclePath, strings.Join(path, "/"))
    
    return v
}

dst := &leptjson.Value{}
leptjson.CustomCopySafeWithReplacement(dst, doc, customReplacer)

技术实现

JSON 指针
  • 使用令牌数组(tokens)表示路径段
  • 实现了完整的 RFC 6901 转义规则
  • 支持相对路径操作
循环引用检测
  • 使用栈结构跟踪访问路径
  • 实现了高效的循环检测算法
  • 使用访问过的节点映射优化替换过程

使用建议

  • 使用 JSON 指针简化复杂 JSON 操作
  • 在处理不可信数据时,使用循环引用检测保证安全
  • 为关键操作添加错误处理
  • 使用自定义替换器创建有意义的循环引用表示

后续改进计划

  • 支持 JSON Patch(RFC 6902)
  • 支持 JSON Merge Patch(RFC 7396)
  • 实现 JSON Schema 验证
  • 添加更多优化和性能改进

Documentation

Overview

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

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

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