我正在请求一个返回包含对象数组的JSON的API。问题是对象可以采用两种形式。它们可以是字符串或对象。示例结果可能如下所示:
[
{"name": "obj1", "key2": ["a", "b"]},
"obj2",
{"name": "obj3"}
]
字符串元素"objX"
相当于{"name": "objX"}
。
我想将其解析为以下类型的片段:
type Obj struct {
Name string
Key2 []string
}
我该如何以合理的方式做到这一点?
答案 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)
}
}
答案 1 :(得分:0)
另一个解决方案是将JSON arrray的各种元素解组为您期望的类型值,并在需要时为Obj
值处理/创建string
包装。
由于您的输入是JSON数组,因此可以将其解组到数组或切片中。由于元素的类型不同,Go数组或切片的元素类型必须为interface{}
。
解组为[]interface{}
类型的值会导致包为对象元素选择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" []}