动态生成json数据
约 977 字大约 3 分钟
2025-05-06
场景分析
与读取指定数据类似, 动态生成json数据也有多种场景, 首先分析下使用诉求:
- 为指定路径设置一个值
- 向数组末尾追加一个元素
- 删除一个路径
- 删除数组末尾元素
- 已有路径数据覆盖
示例如下:
package main
import (
"fmt"
"github.com/tidwall/sjson"
)
func main() {
json := `{
"name": "张三",
"age": 18,
"sex": "男",
"hobby": ["篮球", "足球", "羽毛球"],
"address": {
"province": "广东省",
"city": "深圳市",
"district": "南山区"
}
}`
// 新增数据值
fmt.Println(sjson.Set(json, "ball", "乒乓球"))
// 覆盖字段值
fmt.Println(sjson.Set(json, "name", "李四"))
// 删除路径
fmt.Println(sjson.Delete(json, "ball"))
// 数组末尾追加元素
fmt.Println(sjson.Set(json, "hobby.-1", "乒乓球")))
// 数组末尾删除元素
fmt.Println(sjson.Delete(json, "hobby.-1"))
}
实现分析
以上示例是一个基于gjson的基础实现, 但是, 实际开发中, 不同的项目团队可能会使用不同的json库, 因此, 我们需要根据实际情况进行实现。而要支持各种方式的实现, 为了工程化后有统一的实现标准
,我们需要**抽象出json生成操作的基础能力是什么
**。 json操作的核心基础能力包括:
- 为一个路径设置一个值(包含新增与覆盖)
- 删除一个路径
- 向数组末尾追加一个元素
- 删除数组末尾元素
基于以上核心能力, 来设计后续的实现
接口约束
如前文所述, 与gsjon类似, sjson
已经实现了基础操作, 但是可能并不是赔项目团队的所有项目都使用sjson, 因此, 我们需要对sjson的基础能力进行抽象, 并定义出一个接口, 来约束后续的实现。
// IJsonWrite json数据写入
type IJsonWrite interface {
// Set 设置一个路径的值
Set(dataPath string, data any) error
// Delete 删除一个路径
Delete(dataPath string) error
// Result 最终结果以字符串形式返回
Result() string
// Map 最终结果以map返回
Map() (map[string]any, error)
// MapWithReceiver 外部指针接收返回值
MapWithReceiver(receiver any) error
// Array 最终结果以数组返回
Array() ([]any, error)
// ArrayWithReceiver 外部指针接收返回值
ArrayWithReceiver(receiver any) error
}
具体实现
具体实现不做赘述, 可以以上参考代码。此处只针对上述代码实现中需要注意的内容做重点说明:
- map数据设置如何实现?
在实际应用中, 我们会遇到的实际情况是, 为一个路径设置map值, 但是相关路径已经存在, 此时, 我们需要按照实际需求做出一个抉择: 无差别覆盖还是数据合并
, 上述实例实现中选择的是项目合并的策略进行实现. 那么, 不想要合并, 想要无差别覆盖, 该如何实现呢? 我们可以通过: 可以现将相关路径值设置为nil或者先调用Delete方法删除相关路径, 在设置为想要的值, 曲线实现了覆盖效果
- 数组末尾追加、删除元素如何实现?
数据末尾的追加与删除是sjson提供的能力, 路径设置为 children.-1
即可
- 数据设置/修改的详细逻辑