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 库教程(七):生成器

Go语言实现

本教程是《从零开始的 JSON 库教程》的 Go 语言实现。原始教程由 Milo Yip 编写,主要使用 C 语言。本实现尝试尽可能保持与原始教程相同的结构和概念,同时利用 Go 语言的特性。

教程七:JSON 生成器

在前六个教程中,我们已经实现了一个合规标准的 JSON 解析器,它可以将 JSON 文本解析为树状数据结构。现在,我们将实现 JSON 生成器(generator),它负责将树状数据结构转换回 JSON 文本。这个过程也称为"字符串化(stringify)"。

主要内容
  1. JSON 生成器介绍
  2. 格式化字符串功能
  3. 生成空值、布尔值和数字
  4. 生成字符串(处理转义字符)
  5. 生成数组和对象
修改内容
  • 添加 StringifyError 类型表示生成过程中的错误
  • 添加 Stringify 函数将 Value 转换为 JSON 字符串
  • 实现各种类型值的生成函数
  • 为字符串添加转义处理
  • 递归生成数组和对象类型
实现总结

在本单元中,我们:

  1. 添加了StringifyError类型:与ParseError类似,用于标识字符串化过程中可能出现的错误。

  2. 实现了Stringify函数:将JSON值转换为字符串,返回生成的JSON文本和可能的错误状态。

  3. 使用bytes.Buffer高效构建字符串

    • 利用Go内置的bytes.Buffer类型来高效地构建输出字符串
    • 避免了多次字符串连接可能导致的性能问题
  4. 处理转义字符

    • 特殊处理引号(")、反斜杠(\)、斜杠(/)等需要转义的字符
    • 对控制字符(小于0x20的字符)使用\uXXXX格式进行转义
  5. 递归处理嵌套结构

    • 数组:遍历数组元素,递归调用stringifyValue函数
    • 对象:遍历对象成员,处理键和值
  6. 封装特定类型的处理函数

    • stringifyString:处理字符串值,包括转义处理
    • stringifyArray:处理数组值
    • stringifyObject:处理对象值
性能优化

我们的实现已经相当高效,主要通过以下几点实现:

  1. 使用bytes.Buffer而不是字符串拼接,减少内存分配
  2. 直接将字符写入Buffer而不是创建临时字符串
  3. 对于数字使用内置的strconv.FormatFloat获得最优表示
测试方法

我们使用了多种测试方法确保实现的正确性:

  1. 往返测试:将值转换为JSON,再解析回来,确保解析结果与原始值一致
  2. 单元测试:测试特定情况下的字符串化行为
  3. 基准测试:测量各种类型的字符串化性能
  4. 示例代码:展示API的使用方法
目标

实现一个高效、符合标准的 JSON 生成器,它能够将我们的 Value 数据结构转换为有效的 JSON 文本字符串。

为了简单起见,我们不进行换行、缩进等美化处理,生成的 JSON 将是单行、无空白字符的最紧凑形式。

后续优化方向

尽管当前实现已经能够正常工作,但仍有优化空间:

  1. 提供格式化输出选项,支持缩进和换行
  2. 减少对中间字符串的依赖,进一步提高性能
  3. 提供更多错误类型,以区分不同的错误情况
  4. 添加流式处理大型JSON的能力

Documentation

Overview

leptjson.go - Go语言版JSON库

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func FindObjectIndex

func FindObjectIndex(v *Value, key string) int

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

func GetArraySize

func GetArraySize(v *Value) int

GetArraySize 获取JSON数组的大小

func GetBoolean

func GetBoolean(v *Value) bool

GetBoolean 获取JSON布尔值

func GetNumber

func GetNumber(v *Value) float64

GetNumber 获取JSON数字值

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 SetBoolean

func SetBoolean(v *Value, b bool)

SetBoolean 设置JSON布尔值

func SetNumber

func SetNumber(v *Value, n float64)

SetNumber 设置JSON数字值

func SetString

func SetString(v *Value, s string)

SetString 设置JSON字符串值

Types

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                    // 缺少逗号或花括号
)

解析错误常量

func Parse

func Parse(v *Value, json string) ParseError

Parse 解析JSON文本

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

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 (ParseError) Error

func (e ParseError) Error() string

错误信息

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

错误信息

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 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 (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值的类型

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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