V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
dzdh
V2EX  ›  Go 编程语言

怎么优雅的处理不固定的 json 内容

  •  
  •   dzdh · 2023-07-03 10:56:29 +08:00 · 4532 次点击
    这是一个创建于 389 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如如下 json,怎么写 struct

    {
    "elements": [
        { "type":abc, "这个字段只在 type=abc 时出现":value},
        { "type":def, "这个字段只在 type=def 时出现":value},
        { "abc":"xx" ,"这个字段只在 abc=xx 时出现":"value"}
        ]
    }
    
    38 条回复    2023-07-13 14:11:57 +08:00
    NessajCN
        1
    NessajCN  
       2023-07-03 11:02:25 +08:00
    `json:"字段,omitempty"`
    seers
        2
    seers  
       2023-07-03 11:07:27 +08:00 via Android
    放到 interface
    xdeng
        3
    xdeng  
       2023-07-03 11:08:19 +08:00
    万能的 map[string]any
    jackbrother
        4
    jackbrother  
       2023-07-03 11:11:40 +08:00
    后端设计不合理
    mineralsalt
        5
    mineralsalt  
       2023-07-03 11:14:03 +08:00
    不要映射实体了,这种情况, 还不如直接用 JsonObject 取值来的方便
    bv
        6
    bv  
       2023-07-03 11:14:50 +08:00
    @jackbrother 确实,这个 JSON 一点也不结构化,尤其是多出来的 `"abc":"xx"` 这一项显得数据关系更加松散。
    Seanfuck
        7
    Seanfuck  
       2023-07-03 11:17:49 +08:00
    直接结构体字段写全去解析,没有的字段好像会给个默认值吧?
    yuan1028
        8
    yuan1028  
       2023-07-03 11:19:04 +08:00   ❤️ 1
    struct 为了可读性,最好是把字段都写出来;
    牺牲可读性,为了代码的优雅的话,可以用字符串 json 处理库 https://github.com/tidwall/gjson ,这样不用解析。
    if-else 多,只能用设计模式优化。

    不过,在细微逻辑处,go 还是直来直去更合适,除非业务逻辑也比较明晰。
    exkernel
        9
    exkernel  
       2023-07-03 11:24:05 +08:00
    gjson +1
    HelloAmadeus
        10
    HelloAmadeus  
       2023-07-03 11:31:07 +08:00   ❤️ 1
    就是 oneof 的语法,oneof 也可以理解为 optional ,设计上无外乎两种方式,一种加 type 表示类型,和你这个例子类似,另外一种就是不加 type ,按优先级取值,按你这个例子就是设计上如果存在 "这个字段只在 type=abc 时出现" 对应的值,就不会取 "这个字段只在 type=def 时出现" 这个值了。
    这两种方式,无论怎么样,struct 都要把所有可能的结构都写上,都得写成
    ```
    type Element struct {
    Type string `json:"type"`
    TypeABCValue *struct {
    } `json:"这个字段只在 type=abc 时出现"`
    TypeDEFValue *struct {
    } `json:"这个字段只在 type=def 时出现"`

    ABC string `json:"type"`
    ABCXXValue struct {
    } `json:"这个字段只在 abc=xx 时出现"`
    ```
    ziyeziye
        11
    ziyeziye  
       2023-07-03 11:37:18 +08:00
    gjson +1
    wangritian
        12
    wangritian  
       2023-07-03 11:45:06 +08:00
    这种 key 都不同的还好处理,全声明就完了,赞同 10 楼
    gam2046
        13
    gam2046  
       2023-07-03 12:29:12 +08:00   ❤️ 1
    wheeler
        14
    wheeler  
       2023-07-03 12:38:42 +08:00 via iPhone   ❤️ 1
    rawMessage 根据 type 二次 unmarshal
    Trim21
        15
    Trim21  
       2023-07-03 12:41:45 +08:00 via Android
    如果可能的 key 只有你提到的这 4 5 种的话,像 10 楼那样写个 struct 把所有可能的 key 都写上就好了…
    SimbaPeng
        16
    SimbaPeng  
       2023-07-03 13:08:18 +08:00
    @wheeler 审题朋友,rawMessage 只适合 key 相同的情况,楼主这是 key 都不同
    Aumujun
        17
    Aumujun  
       2023-07-03 13:17:36 +08:00
    gjson ? 取的时候判断一下
    ccde8259
        18
    ccde8259  
       2023-07-03 13:21:50 +08:00 via iPhone
    有的 json 包 unmarshal 出来的是 ast.Node
    otakustay
        19
    otakustay  
       2023-07-03 13:32:59 +08:00
    @jackbrother 也不能说不合理吧,从类型角度考虑这就是个 union type ,要说语言的类型能力不足也行
    a2231243
        20
    a2231243  
       2023-07-03 13:53:18 +08:00
    structpb.Struct 这个挺好用
    janus77
        21
    janus77  
       2023-07-03 13:56:20 +08:00
    这种内容,一般上游是 php ,要么就是这个项目的老架构是用 php 后面改 go 重写的
    mxT52CRuqR6o5
        22
    mxT52CRuqR6o5  
       2023-07-03 13:57:52 +08:00
    abc 这个 key 是动态的?
    dzdh
        23
    dzdh  
    OP
       2023-07-03 14:55:47 +08:00
    @mxT52CRuqR6o5 其他也是动态的。后端是 php 类似 class TypeA impl jsonserialize { tojson: return [type:...
    Justin13
        24
    Justin13  
       2023-07-03 16:54:21 +08:00 via Android
    上 jsonschema
    lisxour
        25
    lisxour  
       2023-07-03 16:58:42 +08:00
    这种就不应该上结构体了,用 gjson 之类的去取
    CloveAndCurrant
        26
    CloveAndCurrant  
       2023-07-03 17:01:52 +08:00
    推荐 fastjson: github.com/valyala/fastjson
    和 fasthttp 一个作者开发的
    shawn4me
        27
    shawn4me  
       2023-07-03 17:06:57 +08:00
    我之前做需求开发的时候也遇到这种动态字段的问题。我通常的做法是:类型作为一个字段,跟着类型变动的其他字段使用 json 字段统一存在一个字段里面。形成一个两级关系,这样就可以放心根据 type 字段进行取用了。Go 用内嵌应该也能做到,再加一个 omitempty 就能避免无用字段出现了。
    bunny189
        28
    bunny189  
       2023-07-03 19:27:40 +08:00
    我个人评价为你们后端有病
    lisongeee
        29
    lisongeee  
       2023-07-03 19:55:25 +08:00
    如果是 typescript/scala 的话,就是一个很简单的 联合类型
    sadfQED2
        30
    sadfQED2  
       2023-07-03 20:18:13 +08:00 via Android
    直接上正则吧,别解析了
    huzhizhao
        31
    huzhizhao  
       2023-07-03 23:56:09 +08:00 via iPhone   ❤️ 1
    不知道什么类型的业务会不抽象🤔
    alexapollo
        32
    alexapollo  
       2023-07-04 00:20:38 +08:00
    条件结构的需求非常常见。比如不同返回码对应了不同的输出 —— 在上古 C 语言时期就已经有大量对应设计。

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

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

    在其他语言中,你也应该搜索:<lang> json union ,来找到一个恰当的实现
    Leviathann
        33
    Leviathann  
       2023-07-04 00:27:47 +08:00
    数组里后面的元素依赖前面的元素的 type 字段?
    什么勾把接口
    cheng6563
        34
    cheng6563  
       2023-07-04 09:23:34 +08:00
    @huzhizhao PHP 后台能给你个 JSON 已经很不错了
    whooami
        35
    whooami  
       2023-07-04 09:57:02 +08:00
    使用 com.google.gson.JsonDeserializer
    troywinter
        36
    troywinter  
       2023-07-04 17:16:38 +08:00
    明显结构设计不合理
    huzhizhao
        37
    huzhizhao  
       2023-07-05 06:47:19 +08:00 via iPhone
    @cheng6563 确实,深有体会
    awanganddong
        38
    awanganddong  
       2023-07-13 14:11:57 +08:00
    这个帖子是一个解决方案
    Go 如何解析 json 内部结构不确定的情况

    https://my.oschina.net/u/4628563/blog/4724059
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2490 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 01:52 · PVG 09:52 · LAX 18:52 · JFK 21:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.