【问题标题】:Unmarshal JSON and differentiate between missing key and null value [duplicate]解组 JSON 并区分缺少的键和空值 [重复]
【发布时间】:2021-05-11 00:54:30
【问题描述】:

我正在使用一个应用程序 API,它以不同的方式处理 JSON 中缺少的键和 null 值。它可能会像{"value":null}{} 一样交还JSON - 如果密钥存在,它们的含义会有所不同。我的问题是我需要将数据解组为struct,然后将其编组回 JSON,保留这种细微差别。

如果我定义这样的结构:

type Test struct {
    Value *string `json:"value,omitempty"`
}

然后{"value":null} 被编组为 JSON 为 {}

如果我定义这样的结构:

type Test struct {
    Value *string `json:"value"`
}

然后{} 被编组为 JSON 为 {"value":null}

有没有办法处理从 JSON 读取的空键和缺失键,并保留缺失键与空值之间的差异?

【问题讨论】:

  • 编组为地图或 json.RawMessage 或自己的 json.Unmarshaler 实现。越来越复杂。

标签: json api go


【解决方案1】:

如果你必须区分字段的空值和不存在,你可以使用json.RawMessage

type Test struct {
    Value json.RawMessage `json:"value,omitempty"`
}

您可以测试string(test.Value)=="null"len(test.Value)==0 以确定发生了哪种情况。

【讨论】:

    【解决方案2】:

    您可以在自定义字符串类型上实现json.Marshalerjson.Unmarshaler 接口,并使用“空字节”来表示null。但是,您需要确保依赖自定义字符串类型的系统的其他部分知道空字节,并且它们会正确处理此类实例。

    type String string
    
    const Null String = "\x00"
    
    func (s *String) UnmarshalJSON(data []byte) error {
        if string(data) == "null" {
            *s = Null
        }
        return json.Unmarshal(data, (*string)(s))
    }
    
    func (s String) MarshalJSON() ([]byte, error) {
        if s == Null {
            return []byte(`null`), nil
        }
        return json.Marshal(string(s))
    }
    

    https://play.golang.org/p/HoiP778TDva

    【讨论】:

    • 最后的string(s) 没有转义。如果它包含",它将产生无效的JSON
    • @colm.anseo 感谢您指出这一点,我已经更新了应该处理这种情况的答案。
    • 您可以直接致电 Marshal:play.golang.org/p/YEEbZp8lu70
    • 几乎 :-) 您的游乐场链接使用 json.Marshal(s) 导致无限递归。应该是:json.Marshal(string(s))
    • -_- 我把这归咎于食物,我吃得太多了。
    猜你喜欢
    • 1970-01-01
    • 2020-06-04
    • 2018-07-18
    • 1970-01-01
    • 2016-01-18
    • 2020-10-21
    • 1970-01-01
    • 2022-06-30
    • 2013-04-24
    相关资源
    最近更新 更多