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解析库的用户友好性和健壮性。这些改进使库更适合在生产环境中使用,特别是在处理不可信数据时。通过提供详细的错误信息和恢复机制,可以帮助开发者更快地定位和解决问题。

Documentation

Overview

leptjson.go - Go语言版JSON库

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ClearArray

func ClearArray(v *Value)

ClearArray 清空数组的所有元素

func ClearObject

func ClearObject(v *Value)

ClearObject 清空对象的所有成员

func Copy

func Copy(dst, src *Value)

Copy 深度复制一个JSON值

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 Move

func Move(dst, src *Value)

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

func PopBackArrayElement

func PopBackArrayElement(v *Value)

PopBackArrayElement 移除数组末尾的元素

func RemoveObjectValue

func RemoveObjectValue(v *Value, index int)

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

func ReserveArray

func ReserveArray(v *Value, capacity int)

ReserveArray 扩充数组容量

func ReserveObject

func ReserveObject(v *Value, capacity int)

ReserveObject 扩充对象容量

func SetArray

func SetArray(v *Value, capacity int)

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

func SetBoolean

func SetBoolean(v *Value, b bool)

SetBoolean 设置JSON布尔值

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 ShrinkArray

func ShrinkArray(v *Value)

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

func ShrinkObject

func ShrinkObject(v *Value)

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

func Swap

func Swap(lhs, rhs *Value)

Swap 交换两个JSON值

Types

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 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文本(使用默认选项)

Example (Array)

示例 - 解析数组

v := Value{}
Parse(&v, "[1,2,3]")
fmt.Println(v.String())
Output:
[1,2,3]
Example (Error)

示例 - 错误处理

v := Value{}
err := Parse(&v, "[1,2,")
fmt.Println(err)
Output:
缺少逗号或方括号
Example (Error02)
v := Value{}
err := Parse(&v, "{\"name\":\"John\",\"age\":")
fmt.Println(err)
Output:
期望一个值
Example (False)

示例 - 解析false值

v := Value{}
Parse(&v, "false")
fmt.Println(v.String())
Output:
false
Example (NestedArray)

示例 - 解析嵌套数组

v := Value{}
Parse(&v, "[[1,2],[3,4],5]")
fmt.Println(v.String())
Output:
[[1,2],[3,4],5]
Example (NestedObject)

示例 - 解析嵌套对象

v := Value{}
Parse(&v, "{\"person\":{\"name\":\"John\",\"age\":30},\"isActive\":true}")
fmt.Println(v.String())
Output:
{"person":{"name":"John","age":30},"isActive":true}
Example (Null)

示例 - 解析null值

v := Value{}
Parse(&v, "null")
fmt.Println(v.String())
Output:
null
Example (Number)

示例 - 解析数字

v := Value{}
Parse(&v, "123.456")
fmt.Println(v.String())
Output:
123.456
Example (Object)

示例 - 解析对象

v := Value{}
Parse(&v, "{\"name\":\"John\",\"age\":30}")
fmt.Println(v.String())
Output:
{"name":"John","age":30}
Example (String)

示例 - 解析字符串

v := Value{}
Parse(&v, "\"Hello, World!\"")
fmt.Println(v.String())
Output:
"Hello, World!"
Example (Stringify)

ExampleParse_stringify 展示解析和字符串化的结合使用

jsonText := `{"a":[1,2],"b":{"c":0,"d":[false,true,null,"Hello"]}}`
var v Value

if err := Parse(&v, jsonText); err == PARSE_OK {
	jsonOut, _ := Stringify(&v)
	fmt.Println(jsonOut)
}
Output:
{"a":[1,2],"b":{"c":0,"d":[false,true,null,"Hello"]}}
Example (True)

示例 - 解析true值

v := Value{}
Parse(&v, "true")
fmt.Println(v.String())
Output:
true

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字符串

Example (Array)

ExampleStringify_array 展示如何字符串化数组值

v := Value{
	Type: ARRAY,
	A: []*Value{
		{Type: NULL},
		{Type: FALSE},
		{Type: TRUE},
		{Type: NUMBER, N: 123},
		{Type: STRING, S: "abc"},
	},
}
json, _ := Stringify(&v)
fmt.Println(json)
Output:
[null,false,true,123,"abc"]
Example (Boolean)

ExampleStringify_boolean 展示如何字符串化布尔值

v1 := Value{Type: TRUE}
json1, _ := Stringify(&v1)
fmt.Println(json1)

v2 := Value{Type: FALSE}
json2, _ := Stringify(&v2)
fmt.Println(json2)
Output:
true
false
Example (Complex)

ExampleStringify_complex 展示如何字符串化复杂值

v := Value{
	Type: OBJECT,
	O: []Member{
		{K: "a", V: &Value{
			Type: ARRAY,
			A: []*Value{
				{Type: NUMBER, N: 1},
				{Type: NUMBER, N: 2},
			},
		}},
		{K: "b", V: &Value{
			Type: OBJECT,
			O: []Member{
				{K: "c", V: &Value{Type: NUMBER, N: 0}},
				{K: "d", V: &Value{
					Type: ARRAY,
					A: []*Value{
						{Type: FALSE},
						{Type: TRUE},
						{Type: NULL},
						{Type: STRING, S: "Hello"},
					},
				}},
			},
		}},
	},
}
json, _ := Stringify(&v)
fmt.Println(json)
Output:
{"a":[1,2],"b":{"c":0,"d":[false,true,null,"Hello"]}}
Example (Null)

ExampleStringify_null 展示如何字符串化null值

v := Value{Type: NULL}
json, _ := Stringify(&v)
fmt.Println(json)
Output:
null
Example (Number)

ExampleStringify_number 展示如何字符串化数字值

v := Value{Type: NUMBER, N: 123.456}
json, _ := Stringify(&v)
fmt.Println(json)
Output:
123.456
Example (Object)

ExampleStringify_object 展示如何字符串化对象值

v := Value{
	Type: OBJECT,
	O: []Member{
		{K: "null", V: &Value{Type: NULL}},
		{K: "false", V: &Value{Type: FALSE}},
		{K: "true", V: &Value{Type: TRUE}},
		{K: "number", V: &Value{Type: NUMBER, N: 123}},
		{K: "string", V: &Value{Type: STRING, S: "abc"}},
	},
}
json, _ := Stringify(&v)
fmt.Println(json)
Output:
{"null":null,"false":false,"true":true,"number":123,"string":"abc"}
Example (String)

ExampleStringify_string 展示如何字符串化字符串值

v := Value{Type: STRING, S: "Hello, World!"}
json, _ := Stringify(&v)
fmt.Println(json)
Output:
"Hello, World!"

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