问题描述
我有一个来自这样的API的JSON响应对象:
[
{
"peoples": {
"1": {"name": "Jhon","age": 123},"2": {"name": "Jhon","3": {"name": "Jhon","4": {"name": "Jhon","_object": true,"_timestamp": "2020-08-05T07:05:55.509Z","_writable": false
}
}
]
参数peoples
,_object
,_timestamp
和_writable
是固定的。动态值是1,2,3,4...n
参数。
该结构中peoples
的数量可以大于4或可以为1。是否有用于创建Struct对象或json.Unmarshal
的优雅解决方案?
解决方法
借用the input example from Sarath Sadasivan Pillai(请参阅comment),here (link to Playground example)是使用map[string]json.RawMessage
和自定义解组功能的一种方法:
package main
import (
"encoding/json"
"fmt"
"strconv"
"time"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
type Keywords struct {
Object bool `json:"_object"`
Timestamp time.Time `json:"_timestamp"`
Writable bool `json:"_writable"`
}
type Decoded struct {
People map[string]Person // or perhaps just []Person
Info Keywords
}
var input []byte = []byte(`{
"1": {"name": "Jhon","age": 123},"2": {"name": "Jhon","3": {"name": "Jhon","4": {"name": "Jhon","_object": true,"_timestamp": "2020-08-05T07:05:55.509Z","_writable": false
}`)
// Unmarshal json in the input format outlined by
// the example above: a map of numeric strings to Name/Age pair,// plus some keywords.
func (d *Decoded) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data,&d.Info); err != nil {
return err
}
var m map[string]json.RawMessage
if err := json.Unmarshal(data,&m); err != nil {
return err
}
if d.People == nil {
d.People = make(map[string]Person)
}
for k := range m {
// This is the hard part: you must choose how
// to decide whether to decode this as a Person.
// Here,we use strconv.Atoi() as in the example
// by Sarath Sadasivan Pillai,but there are as
// many options as you can think of.
//
// For instance,another method would be to try
// decoding the json.RawMessage as a Person. It's
// also not clear whether the numeric values imply
// some particular ordering,which maps discard.
// (If these come out in order,that's just luck.)
if _,err := strconv.Atoi(k); err != nil {
continue
}
var p Person
if err := json.Unmarshal(m[k],&p); err != nil {
return err
}
d.People[k] = p
}
return nil
}
func main() {
var x Decoded
err := json.Unmarshal(input,&x)
if err != nil {
fmt.Printf("failed: %v\n",err)
} else {
fmt.Printf("succeeded:\n%#v\n",x.Info)
for k := range x.People {
fmt.Printf("person %q = %#v\n",k,x.People[k])
}
}
}