Golang Go语言中怎么优雅的处理不固定的 json 内容

发布于 1周前 作者 sinazl 来自 Go语言

比如如下 json,怎么写 struct

{
"elements": [
    { "type":abc, "这个字段只在 type=abc 时出现":value},
    { "type":def, "这个字段只在 type=def 时出现":value},
    { "abc":"xx" ,"这个字段只在 abc=xx 时出现":"value"}
    ]
}

Golang Go语言中怎么优雅的处理不固定的 json 内容

更多关于Golang Go语言中怎么优雅的处理不固定的 json 内容的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

39 回复

json:"字段,omitempty"

更多关于Golang Go语言中怎么优雅的处理不固定的 json 内容的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


放到 interface

万能的 map[string]any

后端设计不合理

不要映射实体了,这种情况, 还不如直接用 JsonObject 取值来的方便

确实,这个 JSON 一点也不结构化,尤其是多出来的 "abc":"xx" 这一项显得数据关系更加松散。

直接结构体字段写全去解析,没有的字段好像会给个默认值吧?

struct 为了可读性,最好是把字段都写出来;
牺牲可读性,为了代码的优雅的话,可以用字符串 json 处理库 https://github.com/tidwall/gjson ,这样不用解析。
if-else 多,只能用设计模式优化。

不过,在细微逻辑处,go 还是直来直去更合适,除非业务逻辑也比较明晰。

就是 oneof 的语法,oneof 也可以理解为 optional ,设计上无外乎两种方式,一种加 type 表示类型,和你这个例子类似,另外一种就是不加 type ,按优先级取值,按你这个例子就是设计上如果存在 “这个字段只在 type=abc 时出现” 对应的值,就不会取 “这个字段只在 type=def 时出现” 这个值了。
这两种方式,无论怎么样,struct 都要把所有可能的结构都写上,都得写成
<br>type Element struct {<br> Type string `json:"type"`<br> TypeABCValue *struct {<br> } `json:"这个字段只在 type=abc 时出现"`<br> TypeDEFValue *struct {<br> } `json:"这个字段只在 type=def 时出现"`<br> <br> ABC string `json:"type"`<br> ABCXXValue struct {<br> } `json:"这个字段只在 abc=xx 时出现"`<br>

这种 key 都不同的还好处理,全声明就完了,赞同 10 楼

rawMessage 根据 type 二次 unmarshal

如果可能的 key 只有你提到的这 4 5 种的话,像 10 楼那样写个 struct 把所有可能的 key 都写上就好了…

审题朋友,rawMessage 只适合 key 相同的情况,楼主这是 key 都不同

gjson ? 取的时候判断一下

有的 json 包 unmarshal 出来的是 ast.Node

也不能说不合理吧,从类型角度考虑这就是个 union type ,要说语言的类型能力不足也行

structpb.Struct 这个挺好用

这种内容,一般上游是 php ,要么就是这个项目的老架构是用 php 后面改 go 重写的

abc 这个 key 是动态的?

其他也是动态的。后端是 php 类似 class TypeA impl jsonserialize { tojson: return [type:…

这种就不应该上结构体了,用 gjson 之类的去取

推荐 fastjson: github.com/valyala/fastjson
和 fasthttp 一个作者开发的

我之前做需求开发的时候也遇到这种动态字段的问题。我通常的做法是:类型作为一个字段,跟着类型变动的其他字段使用 json 字段统一存在一个字段里面。形成一个两级关系,这样就可以放心根据 type 字段进行取用了。Go 用内嵌应该也能做到,再加一个 omitempty 就能避免无用字段出现了。

我个人评价为你们后端有病

如果是 typescript/scala 的话,就是一个很简单的 联合类型

直接上正则吧,别解析了

不知道什么类型的业务会不抽象🤔

条件结构的需求非常常见。比如不同返回码对应了不同的输出 —— 在上古 C 语言时期就已经有大量对应设计。

如: http://c.biancheng.net/view/2035.html 中有 C 语言的 union 例子

在 Python 中,你可以使用支持 Union 类型的库来实现这个功能,比如 pydantic: https://docs.pydantic.dev/latest/usage/types/unions/

在其他语言中,你也应该搜索:<lang> json union ,来找到一个恰当的实现

数组里后面的元素依赖前面的元素的 type 字段?
什么勾把接口

PHP 后台能给你个 JSON 已经很不错了

使用 com.google.gson.JsonDeserializer

明显结构设计不合理

确实,深有体会

这个帖子是一个解决方案
Go 如何解析 json 内部结构不确定的情况

https://my.oschina.net/u/4628563/blog/4724059

在Golang中处理不固定的JSON内容时,优雅的做法通常涉及使用map、interface{}类型以及结构体标签(struct tags)的组合。以下是一些建议:

  1. 使用map[string]interface{}: 当JSON结构未知或变化时,可以将JSON解码到一个map[string]interface{}中。这允许你动态地访问JSON对象的键值对。

    var data map[string]interface{}
    err := json.Unmarshal([]byte(jsonStr), &data)
    if err != nil {
        // 处理错误
    }
    // 访问数据
    value, ok := data["key"].(string)
    if ok {
        fmt.Println(value)
    }
    
  2. 定义部分结构体并使用interface{}: 如果JSON中有部分结构是已知的,可以定义一个结构体来匹配这些已知字段,并将未知字段捕获到interface{}中。

    type KnownFields struct {
        Field1 string `json:"field1"`
        Rest   map[string]interface{} `json:"-"` // 使用json:"-"忽略此字段的直接解析
    }
    
    var kf KnownFields
    json.Unmarshal([]byte(jsonStr), &struct {
        KnownFields
        Rest map[string]interface{} `json:",inline"`
    }{
        Rest: &kf.Rest,
    })
    
  3. 错误处理: 在处理动态JSON时,务必做好错误处理,特别是类型断言(type assertion)失败的情况。

通过上述方法,你可以灵活且优雅地处理不固定的JSON内容,同时保持代码的清晰和可维护性。

回到顶部