mrkong 发表于 2025-8-15 16:12:42

Go-SJSON:JSON 动态修改新方案

本帖最后由 mrkong 于 2025-8-15 16:24 编辑

在 Go 语言的 JSON 处理领域,读取 与 修改 是两个核心需求。前文介绍过的 GJSON 已经很好地解决了灵活读取问题,而它的“姊妹库” SJSON 则专注于实现 无需结构体定义的 JSON 动态修改,与 GJSON 形成完美互补。本文将从原生方案说起,逐步对比 SJSON 的优势与用法。
一、Go 原生 JSON 修改方式Go 原生修改 JSON 的流程通常是:
[*]定义结构体
[*]json.Unmarshal 将 JSON 解析到结构体
[*]修改字段
[*]json.Marshal 转回 JSON
示例:
package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Ageint    `json:"age"`
}

func main() {
    jsonStr := `{"name":"张三","age":25}`

    var person Person
    err := json.Unmarshal([]byte(jsonStr), &person)
    if err != nil {
      fmt.Println("解析错误:", err)
      return
    }

    person.Age = 35
    newJson, _ := json.Marshal(person)

    fmt.Println(string(newJson))
}这种方式虽然类型安全,但在实际业务中存在明显问题:
[*]必须预先定义结构体,缺少灵活性
[*]未定义字段会丢失,难以保持原始结构完整
[*]嵌套结构或动态字段路径处理繁琐

二、SJSON 简介SJSON 是 tidwall 团队开发的一个轻量库,支持直接通过路径表达式修改 JSON 字符串,无需定义结构体。它与 GJSON 使用相同的路径语法,因此可以无缝组合,实现 JSON 的“读写闭环”。
[*]特点:

[*]无需结构体,直接操作 JSON 字符串
[*]支持嵌套结构和数组的修改、追加
[*]保留原有字段,不会丢失未修改的内容
[*]支持动态路径,运行时灵活构建
安装:go get -u github.com/tidwall/sjson三、SJSON 核心用法
1. 基础值修改
package main

import (
    "fmt"
    "github.com/tidwall/sjson"
)

func main() {
    jsonStr := `{"name":"张三","age":25}`

    // 修改 age 值为 35
    newJson, _ := sjson.Set(jsonStr, "age", 35)

    fmt.Println(newJson)
}
2. 嵌套结构修改
package main

import (
    "fmt"
    "github.com/tidwall/sjson"
)

func main() {
    jsonStr := `{
       "name": "张三",
       "age": 25,
       "hobby": {
          "sing": "只因你太美",
          "dance": "背带裤",
          "rap": "kun",
          "ball": "篮球"
       }
    }`

    // 修改 hobby.sing
    newJson, _ := sjson.Set(jsonStr, "hobby.sing", "重生")

    fmt.Println(newJson)
}
3. 数组操作
package main

import (
    "fmt"
    "github.com/tidwall/sjson"
)

func main() {
    jsonStr := `{"hobby": ["sing","dance","rap","ball"]}`

    // 修改数组第 4 个元素
    newJson, _ := sjson.Set(jsonStr, "hobby.3", "play")
    fmt.Println(newJson)

    // 追加元素
    newJson, _ = sjson.Set(jsonStr, "hobby.-1", "read")
    fmt.Println(newJson)
}
4. 字段删除
package main

import (
    "fmt"
    "github.com/tidwall/sjson"
)

func main() {
    jsonStr := `{"name":"张三","age":25}`

    // 删除 age 字段
    newJson, _ := sjson.Delete(jsonStr, "age")

    fmt.Println(newJson)
}

四、SJSON vs 原生方案
对比项Go 原生方案SJSON
结构体定义必须提前定义无需定义
保留未知字段❌ 丢失未定义字段✅ 完全保留
嵌套字段修改繁琐路径直达
动态路径不便灵活支持
性能一般高效,内部优化
总结:
[*]如果你需要类型安全、编译期检查,用原生方式更稳妥
[*]如果你需要动态修改、保留原结构、快速迭代,SJSON 无疑是更优选择
五、与 GJSON 组合由于 GJSON 与 SJSON 使用相同的路径语法,你可以:GJSON 用于读取:value := gjson.Get(jsonStr, "hobby.sing").String()
SJSON 用于修改:newJson, _ := sjson.Set(jsonStr, "hobby.sing", "重生")
这样即可形成“读取 → 修改 → 输出”的高效链路,完全不需要结构体定义。
六、结语在动态 JSON 修改场景下,SJSON 可以让我们摆脱结构体的束缚,减少冗余代码,并保持 JSON 的完整性。配合 GJSON 使用,可以极大提升开发效率。
页: [1]
查看完整版本: Go-SJSON:JSON 动态修改新方案