将多个JSON类型解析为相同的结构

时间:2017-11-01 14:31:12

标签: json go

我正在请求一个返回包含对象数组的JSON的API。问题是对象可以采用两种形式。它们可以是字符串或对象。示例结果可能如下所示:

[
    {"name": "obj1", "key2": ["a", "b"]},
    "obj2",
    {"name": "obj3"}
]

字符串元素"objX"相当于{"name": "objX"}

我想将其解析为以下类型的片段:

type Obj struct {
    Name string
    Key2 []string
}

我该如何以合理的方式做到这一点?

2 个答案:

答案 0 :(得分:2)

package main

import (
    "encoding/json"
    "fmt"
)

type Obj struct {
    Name string   `json:"name"`
    Key2 []string `json:"key2"`
}

func (o *Obj) UnmarshalJSON(b []byte) error {
    var name string
    if err := json.Unmarshal(b, &name); err == nil {
        *o = Obj{}
        o.Name = name
        return nil
    }

    type Obj2 Obj
    var o2 Obj2
    if err := json.Unmarshal(b, &o2); err != nil {
        return err
    }
    *o = Obj(o2)
    return nil
}

const payload = `[
    {"name": "obj1", "key2": ["a", "b"]},
    "obj2",
    {"name": "obj3"}
]
`

func main() {
    var objs []*Obj
    if err := json.Unmarshal([]byte(payload), &objs); err != nil {
        panic(err)
    }
    for _, obj := range objs {
        fmt.Printf("Name:%v, Key2:%v\n", obj.Name, obj.Key2)
    }
}

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

答案 1 :(得分:0)

另一个解决方案是将JSON arrray的各种元素解组为您期望的类型值,并在需要时为Obj值处理/创建string包装。

由于您的输入是JSON数组,因此可以将其解组到数组或切片中。由于元素的类型不同,Go数组或切片的元素类型必须为interface{}

解组为[]interface{}类型的值会导致tboard_image_2dhist包为对象元素选择map[string]interface{}。但是,如果您之前使用要解组的类型的元素填充目标切片,json包将顺从地使用这些:

func main() {
    res := []interface{}{
        &Obj{},
        "",
        &Obj{},
    }
    if err := json.Unmarshal([]byte(src), &res); err != nil {
        panic(err)
    }

    for _, v := range res {
        fmt.Printf("type = %-10T value = %+q\n", v, v)
    }
}

const src = `[
    {"name": "obj1", "key2": ["a", "b"]},
    "obj2",
    {"name": "obj3"}
]`

输出(在encoding/json上尝试):

type = *main.Obj  value = &{"obj1" ["a" "b"]}
type = string     value = "obj2"
type = *main.Obj  value = &{"obj3" []}