假设我有一个JSON消息,看起来像这样:

{
    "type": string
    "data": list of something that is based on above type
}

两个例子可能是

{
    "type": "car"
    "data": [{"color": "red", "mpg": 16.4}]
}

{
    "type": "house"
    "data": [{"color": "blue", "state": "CA"}]
}

I want to define a struct so I can basically only decode the type 和 then use that to properly unmarshal the data field. I tried the following

type message struct {
    Type string `json:"type"`
    Data []byte `json:"data"`
}

type car struct {
    Color string
    MPG   float64
}

type house struct {
    Color string
    State string
}

erroneously thinking that it would just leave the Data field raw for me to unmarshal later into either the car or house struct. I know I can define Data as a []interface{} 和 do some other work to get what I want, but I was wondering if this is (currently) the best way in Go? In case it comes up, assume I cannot change the JSON definitions - I'm just the consumer of a service here.

推荐答案

这是一个完美的json.RawMessage个用例.看看这里的Unmarshal个例子.

对于您的示例,这将看起来像:

type message struct {
    Type string            `json:"type"`
    Data []json.RawMessage `json:"data"`
}

type car struct {
    Color string
    MPG   float64
}

type house struct {
    Color string
    State string
}

func main() {
    if err := parseAndPrint(carJSON); err != nil {
        panic(err)
    }
    if err := parseAndPrint(houseJSON); err != nil {
        panic(err)
    }
}

func parseAndPrint(b []byte) error {
    msg := new(message)
    if err := json.Unmarshal(b, msg); err != nil {
        panic(err)
    }

    switch msg.Type {
    case "car":
        for _, data := range msg.Data {
            c := new(car)
            if err := json.Unmarshal(data, c); err != nil {
                return err
            }
            fmt.Println(c)
        }
    case "house":
        for _, data := range msg.Data {
            h := new(house)
            if err := json.Unmarshal(data, h); err != nil {
                return err
            }
            fmt.Println(h)
        }
    }
    return nil
}


// Tucked here to get out of the way of the example
var carJSON = []byte(`
{
    "type": "car",
    "data": [{"color": "red", "mpg": 16.4}]
}
`)

var houseJSON = []byte(`{
    "type": "house",
    "data": [{"color": "blue", "state": "CA"}]
}
`)

现在,您如何处理解析的结果,这取决于您和您的程序的需要.在边缘处解析并只传递完整类型的消息,在外部 struct 中添加一个Parsed any字段,等等.

Json相关问答推荐

将嵌套的json中的字符串强制转换为数字

如何在PowerShell中扩展JSON中的嵌套数组

GO KaZaam转换返回意外结果

解析SQL中的嵌套JSON

使用自定义类型在Golang中解析JSON数组

当由.sh脚本执行时,AWS查询字符串不会提取任何数据

Golang jsonrpc2 服务器在哪里监听?

APIM 生成 JsonArray 到 EventHub

jq :当路径可变时更新 json 内容

try 使用 JQ 转换 JSON 中过于复杂的对象数组

将来自 Golang 的 JSON API 调用响应输出到 nextjs 前端

Powershell 7.2:ConvertFrom-Json - 日期处理

嵌套 JSON 到 CSV(多级)

从 PowerShell 编辑 Windows 终端配置文件设置 JSON

JOLT 转换 - 删除 JSON 数组中的空 node

从 json 数组中仅提取一个值导致 vb6

从 Postgres 中的 json 对象中提取键、值

我应该如何处理 JSON 中的 HATEOAS 链接和引用?

关于使用 $ref 的 JSON 模式

如何在 Python 中合并两个 json 字符串?