json - 使用 json.RawMessage 将 json 解码为结构

标签 json go unmarshalling

我需要解码可能具有以下格式的 json 对象:

格式一:

{
    "contactType": 2,
    "value": "0123456789"
}

格式2:

{
    "contactType": "MobileNumber",
    "value": "0123456789"
}

我用于解码的结构是:-

type Contact struct {
    ContactType int    `json:"contactType"` 
    Value       string `json:"value"`
}

但这仅适用于格式 1。我不想更改 ContactType 的数据类型,但我也想适应第二种格式。我听说过 json.RawMarshal 并尝试使用它。

type Contact struct {
    ContactType int
    Value       string          `json:"value"`
    Type        json.RawMessage `json:"contactType"`
}

type StringContact struct {
    Type string `json:"contactType"`
}

type IntContact struct {
    Type int `json:"contactType"`
} 

这完成了解码,但我无法设置 ContactType 变量,该变量取决于 json.RawMessage 的类型。如何为我的结构建模才能解决这个问题?

最佳答案

您需要自己进行解码。有一篇非常好的文章展示了如何正确使用 json.RawMessage 以及针对这个问题的许多其他解决方案,例如使用接口(interface)、RawMessage、实现您自己的解码和解码功能等。

您可以在此处找到该文章:JSON decoding in GO by Attila Oláh 注意:Attila 在他的代码示例中犯了一些错误。

我冒昧地整理(使用来自 Attila 的一些代码)一个使用 RawMessage 延迟解码的工作示例,这样我们就可以在我们自己的解码函数版本上完成它。

Link to GOLANG Playground

package main

import (
    "fmt"
    "encoding/json"
    "io"
)

type Record struct {
    AuthorRaw json.RawMessage `json:"author"`
    Title     string          `json:"title"`
    URL       string          `json:"url"`

    Author Author
}

type Author struct {
    ID    uint64 `json:"id"`
    Email string `json:"email"`
}

func Decode(r io.Reader) (x *Record, err error) {
    x = new(Record)
    if err = json.NewDecoder(r).Decode(x); err != nil {
        return
    }
    if err = json.Unmarshal(x.AuthorRaw, &x.Author); err == nil {
        return
    }
    var s string
    if err = json.Unmarshal(x.AuthorRaw, &s); err == nil {
        x.Author.Email = s
        return
    }
    var n uint64
    if err = json.Unmarshal(x.AuthorRaw, &n); err == nil {
        x.Author.ID = n
    }
    return
}

func main() {

    byt_1 := []byte(`{"author": 2,"title": "some things","url": "https://stackoverflow.com"}`)

    byt_2 := []byte(`{"author": "Mad Scientist","title": "some things","url": "https://stackoverflow.com"}`)

    var dat Record

    if err := json.Unmarshal(byt_1, &dat); err != nil {
            panic(err)
    }
    fmt.Printf("%#s\r\n", dat)

    if err := json.Unmarshal(byt_2, &dat); err != nil {
            panic(err)
    }
    fmt.Printf("%#s\r\n", dat)
}

希望这对您有所帮助。

关于json - 使用 json.RawMessage 将 json 解码为结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39223754/

相关文章:

bash - `git clone` 到 $GOPATH 没有 `go get` ?

go - json 字符串不会用 json api.Unmarshal Payload 解码

javascript - 将额外属性附加到 JSON 对象

ios - 如何使用 SwiftyJSON 遍历 JSON?

javascript - 如何循环遍历 json 列表 Ajax/Javascript 中的元素

java - MOXy 的解码不一致

json - 将通用 JSON 对象解码为多种格式之一

javascript - knockout 映射 : JSON grows when mapping and saving multiple times

Golang 新的内存分配

go - 在 IntelliJ 中导入 Go 项目不起作用