Golang Go语言中如何解析动态类型的 JSON?

样例

{
    "video": [
        1,
        2,
        3
    ],
    "video": {
        "a": {
            "aa": []
        }
    },
    "video_type": "template_a"
}

需求

就像样例中那样,video 字段的类型有好几种,具体哪种是通过 video_type 字段决定。

那么对于这种样子的 json ,使用 Golang 应该如何优雅的解析呢?

(问为什么设计成样子的结构,以及解决方案是修改 json 的算了,人家已经定义好了,跑了好几年,不可能因为我改)


Golang Go语言中如何解析动态类型的 JSON?

更多关于Golang Go语言中如何解析动态类型的 JSON?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

19 回复

先写一个结构体来解析对应的 video type 然后根据不同的 type 去用不同的结构体去解析 video 字段
或者使用一个叫 gjson 的库试试

更多关于Golang Go语言中如何解析动态类型的 JSON?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如果是 kotlin 可以用 密封类,如果是 typescript 可以用联合类型,如果是 go ,我不到啊

用 DOM 风格的 json 解析库。

先解析到只有一个字段 video_type 的 struct 上,然后判断类型后选择对应的 struct 再解析

如果每种 video 类型的格式固定,那就好办了

把 video 字段定义为 json.RawMessage ,然后根据 type 再进一步 Unmarshal 即可。

把 video_type 对应的 struct 都枚举出来

go 的话,gjson 类似的库?

if x.Get(“XX”).IsArray IsFloat / x.Get(“XX”).Array()[0].IsFloat/IsArray

gjson \ jsonparser

用 gjson 解析很方便

用 map[string]interface{} 根据 template 解析

Jackson 的话,继承 JsonDeserializer 然后自己一个字段一个字段的解析就行了。

Go 的 interface 和 map[string] 不是万能的?别的语言还要考虑塞个变体

#5 正解,文档里的 example 和你的场景完全一致 https://pkg.go.dev/encoding/json#example-RawMessage-Unmarshal

我用的 github.com/bitly/go-simplejson ,然后使用 simplejson.NewJson(bytes)反序列化,接着用 GetXXX 、SetXXX

不需要定义任何结构体,可参考官方例子: https://github.com/bitly/go-simplejson/blob/master/simplejson_test.go

先把 json decode 到 map[string]any
然后 switch m[video_type]
最后用 mapstructure 把 m[video] decode 到对应的 Struct

在Golang中解析动态类型的JSON,通常使用标准库中的encoding/json包,特别是json.RawMessage类型和map[string]interface{}结构。

  1. 使用json.RawMessage: json.RawMessage是一个原始的JSON数据表示,可以在解析时保留原始数据,稍后再进行进一步解析。适用于不确定JSON结构或需要延迟解析某些字段的情况。

    var raw json.RawMessage
    err := json.Unmarshal([]byte(jsonData), &raw)
    if err != nil {
        // 处理错误
    }
    // 稍后解析raw
    var specificStruct SomeStruct
    err = json.Unmarshal(raw, &specificStruct)
    if err != nil {
        // 处理错误
    }
    
  2. 使用map[string]interface{}: 当JSON结构未知且需要灵活处理时,可以使用map[string]interface{}来解析。interface{}可以表示任意类型,使得解析后的数据非常灵活。

    var data map[string]interface{}
    err := json.Unmarshal([]byte(jsonData), &data)
    if err != nil {
        // 处理错误
    }
    // 访问数据,例如
    value, ok := data["someKey"].(string)
    if ok {
        fmt.Println(value)
    }
    

这两种方法各有优缺点,选择哪种取决于具体需求。json.RawMessage适合需要延迟解析或保留原始数据的场景,而map[string]interface{}则提供了更高的灵活性,但使用时需要注意类型断言以避免运行时错误。

回到顶部