如何在Golang中解码复杂的未命名JSON

时间:2017-10-30 22:50:31

标签: json go decode

我目前正在尝试解码以下JSON结构:

[
    {
        "2015-08-14 19:29:48-04:00": {
            "value": "0.1",
            "measurement_tag_id": "0.1.1a",
            "UTC_time": "2015-08-14 23:29:48",
            "error": "0"
        }
    },
    {
        "2015-08-14 19:37:07-04:00": {
            "value": "0.1",
            "measurement_tag_id": "0.1.1b",
            "UTC_time": "2015-08-14 23:37:07",
            "error": "0"
        }
    },
    {
        "2015-08-14 19:44:16-04:00": {
            "value": "0.1",
            "measurement_tag_id": "0.1.1b",
            "UTC_time": "2015-08-14 23:44:16",
            "error": "0"
        }
    }
]

这最终会有一片Reading结构,格式如下:

type reading struct {
    Value   string `json:"value"`
    MTID    string `json:"measurement_tag_id"`
    UTCTime string `json:"UTC_time"`
    Error   string `json:"error"`
}

我想将其添加到嵌套为:

的现有结构中
type site struct {
    Name string
    ID   string
    Tags []tag
}

type tag struct {
    ID       string
    Readings []reading
}

我目前能够使用适当的密钥从更典型的JSON有效负载中为站点和标记创建基础结构。虽然在弄清楚如何解码阅读JSON时,我一直没有成功。到目前为止,我最接近的是通过map[string]interface{}链接,但这感觉非常笨重和冗长。

到目前为止

解决方案供参考:

var readingData []interface{}
    if err := json.Unmarshal(file, &readingData); err != nil {
        panic(err)
    }
    readings := readingData[0].(map[string]interface{})
    firstReading := readings["2015-08-14 19:29:48-04:00"].(map[string]interface{})
    fmt.Println(firstReading)
    value := firstReading["value"].(string)
    error := firstReading["error"].(string)
    MTID := firstReading["measurement_tag_id"].(string)
    UTCTime := firstReading["UTC_time"].(string)
    fmt.Println(value, error, MTID, UTCTime)

虽然我不确定它是否必要,但我还想保留任意日期键。我的第一个想法是创建一个返回map[string]reading的函数,但我不确定这是多么可行。

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

您可以让reading类型实现json.Unmarshaler界面。

func (r *reading) UnmarshalJSON(data []byte) error {
    type _r reading // same structure, but no methods, avoids infinite calls to this method
    m := map[string]_r{}
    if err := json.Unmarshal(data, &m); err != nil {
        return err
    }
    for _, v := range m {
        *r = reading(v)
    }
    return nil
}

https://play.golang.org/p/7X1oB77XL4

答案 1 :(得分:1)

另一种方法是使用一片地图进行解析,然后复制到一些读数,例如:

    var readingMaps []map[string]reading //slice of maps of string key to reading value

    if err := json.Unmarshal([]byte(data), &readingMaps); err != nil {
        panic(err)
    }

    readings := []reading{}

    for _, m := range readingMaps {
        for _, r := range m {
            readings = append(readings, r)
        }
    }

play.golang.org/p/jXTdmaZz7s