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

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

  •  
  •   dzdh · 299 天前 · 4441 次点击
    这是一个创建于 299 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如如下 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  
       299 天前
    `json:"字段,omitempty"`
    seers
        2
    seers  
       299 天前 via Android
    放到 interface
    xdeng
        3
    xdeng  
       299 天前
    万能的 map[string]any
    jackbrother
        4
    jackbrother  
       299 天前
    后端设计不合理
    mineralsalt
        5
    mineralsalt  
       299 天前
    不要映射实体了,这种情况, 还不如直接用 JsonObject 取值来的方便
    bv
        6
    bv  
       299 天前
    @jackbrother 确实,这个 JSON 一点也不结构化,尤其是多出来的 `"abc":"xx"` 这一项显得数据关系更加松散。
    Seanfuck
        7
    Seanfuck  
       299 天前
    直接结构体字段写全去解析,没有的字段好像会给个默认值吧?
    yuan1028
        8
    yuan1028  
       299 天前   ❤️ 1
    struct 为了可读性,最好是把字段都写出来;
    牺牲可读性,为了代码的优雅的话,可以用字符串 json 处理库 https://github.com/tidwall/gjson ,这样不用解析。
    if-else 多,只能用设计模式优化。

    不过,在细微逻辑处,go 还是直来直去更合适,除非业务逻辑也比较明晰。
    exkernel
        9
    exkernel  
       299 天前
    gjson +1
    HelloAmadeus
        10
    HelloAmadeus  
       299 天前   ❤️ 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  
       299 天前
    gjson +1
    wangritian
        12
    wangritian  
       299 天前
    这种 key 都不同的还好处理,全声明就完了,赞同 10 楼
    wheeler
        14
    wheeler  
       299 天前 via iPhone   ❤️ 1
    rawMessage 根据 type 二次 unmarshal
    Trim21
        15
    Trim21  
       299 天前 via Android
    如果可能的 key 只有你提到的这 4 5 种的话,像 10 楼那样写个 struct 把所有可能的 key 都写上就好了…
    SimbaPeng
        16
    SimbaPeng  
       299 天前
    @wheeler 审题朋友,rawMessage 只适合 key 相同的情况,楼主这是 key 都不同
    Aumujun
        17
    Aumujun  
       299 天前
    gjson ? 取的时候判断一下
    ccde8259
        18
    ccde8259  
       299 天前 via iPhone
    有的 json 包 unmarshal 出来的是 ast.Node
    otakustay
        19
    otakustay  
       299 天前
    @jackbrother 也不能说不合理吧,从类型角度考虑这就是个 union type ,要说语言的类型能力不足也行
    a2231243
        20
    a2231243  
       299 天前
    structpb.Struct 这个挺好用
    janus77
        21
    janus77  
       299 天前
    这种内容,一般上游是 php ,要么就是这个项目的老架构是用 php 后面改 go 重写的
    mxT52CRuqR6o5
        22
    mxT52CRuqR6o5  
       299 天前
    abc 这个 key 是动态的?
    dzdh
        23
    dzdh  
    OP
       299 天前
    @mxT52CRuqR6o5 其他也是动态的。后端是 php 类似 class TypeA impl jsonserialize { tojson: return [type:...
    Justin13
        24
    Justin13  
       299 天前 via Android
    上 jsonschema
    lisxour
        25
    lisxour  
       299 天前
    这种就不应该上结构体了,用 gjson 之类的去取
    CloveAndCurrant
        26
    CloveAndCurrant  
       299 天前
    推荐 fastjson: github.com/valyala/fastjson
    和 fasthttp 一个作者开发的
    shawn4me
        27
    shawn4me  
       299 天前
    我之前做需求开发的时候也遇到这种动态字段的问题。我通常的做法是:类型作为一个字段,跟着类型变动的其他字段使用 json 字段统一存在一个字段里面。形成一个两级关系,这样就可以放心根据 type 字段进行取用了。Go 用内嵌应该也能做到,再加一个 omitempty 就能避免无用字段出现了。
    bunny189
        28
    bunny189  
       299 天前
    我个人评价为你们后端有病
    lisongeee
        29
    lisongeee  
       299 天前
    如果是 typescript/scala 的话,就是一个很简单的 联合类型
    sadfQED2
        30
    sadfQED2  
       299 天前 via Android
    直接上正则吧,别解析了
    huzhizhao
        31
    huzhizhao  
       299 天前 via iPhone   ❤️ 1
    不知道什么类型的业务会不抽象🤔
    alexapollo
        32
    alexapollo  
       299 天前
    条件结构的需求非常常见。比如不同返回码对应了不同的输出 —— 在上古 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  
       298 天前
    数组里后面的元素依赖前面的元素的 type 字段?
    什么勾把接口
    cheng6563
        34
    cheng6563  
       298 天前
    @huzhizhao PHP 后台能给你个 JSON 已经很不错了
    whooami
        35
    whooami  
       298 天前
    使用 com.google.gson.JsonDeserializer
    troywinter
        36
    troywinter  
       298 天前
    明显结构设计不合理
    huzhizhao
        37
    huzhizhao  
       297 天前 via iPhone
    @cheng6563 确实,深有体会
    awanganddong
        38
    awanganddong  
       289 天前
    这个帖子是一个解决方案
    Go 如何解析 json 内部结构不确定的情况

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