golang unmarshal map [string] interface {}到包含带meta元数组的struct

问题描述 投票:1回答:1

我通过API获得以下json数据。我想将这些数据解组为不同的结构方式,如下所述。我怎么能以优雅的方式做到这一点?

{
    "_meta": {
        "count": 2,
        "total": 2
    },
    "0": {
        "key": "key0",
        "name": "name0"
    },
    "1": {
        "key": "key1",
        "name": "name1"
    },
    "2": {
        "key": "key2",
        "name": "name2"
    }
    // It goes on..
}
type Data struct {
   Meta Meta `json:"_meta,omitempty"`
   Elements []Element
}

type Element struct {
   Key string
   Name string
}

type Meta struct{
   Count int
   Total int
}
go unmarshalling
1个回答
2
投票

这可能非常棘手,因为你有一个包含所有内容的json对象。所以我采用解组的方法将字符串映射到* json.RawMessage,然后从那里修复结构。

要做到这一点,您将使用自定义Unmarshaler,它的好处是您可以延迟实际解析内部消息,直到您需要它们为止。

因此,例如,如果您的元字段错误或它所说的数字与地图-1的长度不匹配,您可能会提前退出。

package main

import (
        "encoding/json"
        "fmt"
)

type jdata map[string]*json.RawMessage

type data struct {
        Meta     Meta
        Elements []Element
}

//Element is a key val assoc
type Element struct {
        Key  string
        Name string
}

//Meta holds counts and total of elems
type Meta struct {
        Count int
        Total int
}

var datain = []byte(`
{
    "_meta": {
        "count": 2,
        "total": 2
    },
    "0": {
        "key": "key0",
        "name": "name0"
    },
    "1": {
        "key": "key1",
        "name": "name1"
    },
    "2": {
        "key": "key2",
        "name": "name2"
    }
}`)

func (d *data) UnmarshalJSON(buf []byte) (err error) {
        var (
                meta *json.RawMessage
                ok   bool
        )
        jdata := new(jdata)

        if err = json.Unmarshal(buf, jdata); err != nil {
                return
        }
        if meta, ok = (*jdata)["_meta"]; !ok {
                return fmt.Errorf("_meta field not found in JSON")
        }
        if err = json.Unmarshal(*meta, &d.Meta); err != nil {
                return
        }
        for k, v := range *jdata {
                if k == "_meta" {
                        continue
                }
                elem := &Element{}
                if err = json.Unmarshal(*v, elem); err != nil {
                        return err
                }
                d.Elements = append(d.Elements, *elem)
        }
        return nil

}

func main() {
        data := &data{}
        if err := data.UnmarshalJSON(datain); err != nil {
                panic(err)
        }
        fmt.Printf("decoded:%v\n", data)
}
© www.soinside.com 2019 - 2024. All rights reserved.