英文:
Unmarshal Dynamic JSON
问题
我从一个遵循以下模式的API接收到动态JSON数据:
{
"ts": 时间戳,
"data": [
[ 代码1, 数据1 ],
[ 代码2, 数据2 ],
...
]
}
例如,原始数据如下:
var streamSnapshot = []byte(
`{
"ts": 1496244373.04,
"data":[
["xrate", {"rate":1.2916,"ccy":"USD"}],
["balance",
{
"open_stake":["GBP", 0.0],
"balance":["GBP", 0.0]
}
],
["event",
{
"competition_id":"545",
"ir_status":"pre_event",
"start_time":"2017-09-10T17:00:00+00:00",
"competition_name":"USA NFL",
"event_id":"2017-09-10,21617,21635",
"home":"Buffalo Bills",
"away":"New York Jets",
"sport":"af",
"competition_country":"US"
}
],
["sync", {"Token":"eb1c57132d004f8d8fb967c076921fac"}]
]
}`)
考虑到我们想避免像这样解组到以下结构体的情况:
type StreamMessage struct {
Data [][]interface{} `json:"data"`
Ts float64 `json:"ts"`
}
在这种情况下,我们需要像这样将数据转换回来:
m := raw.(map[string]interface{})
switch messageType {
case XRATE:
xrate := XRate{
Message: Message{
Type: XRATE,
TimeStamp: msg.Ts,
},
rate: m["rate"].(float64),
ccy: m["ccy"].(string),
}
...
有什么更好的解组方法吗?
英文:
I receive dynamic JSON from an API that follows this pattern:
{
"ts": timestamp,
"data": [
[ code1, payload1 ],
[ code2, payload2 ],
...
]
}
For example the raw data will be:
var streamSnapshot = []byte(
`{
"ts": 1496244373.04,
"data":[
["xrate", {"rate":1.2916,"ccy":"USD"}],
["balance",
{
"open_stake":["GBP", 0.0],
"balance":["GBP", 0.0]
}
],
["event",
{
"competition_id":"545",
"ir_status":"pre_event",
"start_time":"2017-09-10T17:00:00+00:00",
"competition_name":"USA NFL",
"event_id":"2017-09-10,21617,21635",
"home":"Buffalo Bills",
"away":"New York Jets",
"sport":"af",
"competition_country":"US"
}
],
["sync", {"Token":"eb1c57132d004f8d8fb967c076921fac"}]
]
}`)
Considering that we want to avoid unmarshalling to a struct like this:
type StreamMessage struct {
Data [][]interface{} `json:"data"`
Ts float64 `json:"ts"`
}
where we would have to cast the data back like:
m := raw.(map[string]interface{})
switch messageType {
case XRATE:
xrate := XRate{
Message: Message{
Type: XRATE,
TimeStamp: msg.Ts,
},
rate: m["rate"].(float64),
ccy: m["ccy"].(string),
}
...
What would be the better way of unmarshalling this?
答案1
得分: 1
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
)
type StreamMessage struct {
Data []*Data `json:"data"`
Ts float64 `json:"ts"`
}
type Data struct {
Type string
XRate *XRateData
Balance *BalanceData
Event *EventData
Sync *SyncData
}
func (d *Data) UnmarshalJSON(b []byte) error {
dec := json.NewDecoder(bytes.NewReader(b))
t, _ := dec.Token()
if delim, ok := t.(json.Delim); !ok || delim != '[' {
return errors.New("expecting data to be an array")
}
if err := dec.Decode(&d.Type); err != nil {
return err
}
var err error
switch d.Type {
case "xrate":
err = dec.Decode(&d.XRate)
case "sync":
err = dec.Decode(&d.Sync)
case "balance":
err = dec.Decode(&d.Balance)
case "event":
err = dec.Decode(&d.Event)
default:
return errors.New("unknown data type " + d.Type)
}
if err != nil {
return err
}
t, _ = dec.Token()
if delim, ok := t.(json.Delim); !ok || delim != ']' {
return errors.New("expecting array to be two elements")
}
return nil
}
type XRateData struct {
Rate json.Number `json:"rate"`
CCY string `json:"ccy"`
}
type BalanceData struct {
// TODO
}
type EventData struct {
// TODO
}
type SyncData struct {
Token string `json:"Token"`
}
var streamSnapshot = []byte(
`{
"ts": 1496244373.04,
"data":[
["xrate", {"rate":1.2916,"ccy":"USD"}],
["balance",
{
"open_stake":["GBP", 0.0],
"balance":["GBP", 0.0]
}
],
["event",
{
"competition_id":"545",
"ir_status":"pre_event",
"start_time":"2017-09-10T17:00:00+00:00",
"competition_name":"USA NFL",
"event_id":"2017-09-10,21617,21635",
"home":"Buffalo Bills",
"away":"New York Jets",
"sport":"af",
"competition_country":"US"
}
],
["sync", {"Token":"eb1c57132d004f8d8fb967c076921fac"}]
]
}`)
func main() {
var sm StreamMessage
if err := json.Unmarshal(streamSnapshot, &sm); err != nil {
panic(err)
}
fmt.Println(sm)
}
链接:https://play.golang.org/p/ktABS6z40m
英文:
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
)
type StreamMessage struct {
Data []*Data `json:"data"`
Ts float64 `json:"ts"`
}
type Data struct {
Type string
XRate *XRateData
Balance *BalanceData
Event *EventData
Sync *SyncData
}
func (d *Data) UnmarshalJSON(b []byte) error {
dec := json.NewDecoder(bytes.NewReader(b))
t, _ := dec.Token()
if delim, ok := t.(json.Delim); !ok || delim != '[' {
return errors.New("expecting data to be an array")
}
if err := dec.Decode(&d.Type); err != nil {
return err
}
var err error
switch d.Type {
case "xrate":
err = dec.Decode(&d.XRate)
case "sync":
err = dec.Decode(&d.Sync)
case "balance":
err = dec.Decode(&d.Balance)
case "event":
err = dec.Decode(&d.Event)
default:
return errors.New("unknown data type " + d.Type)
}
if err != nil {
return err
}
t, _ = dec.Token()
if delim, ok := t.(json.Delim); !ok || delim != ']' {
return errors.New("expecting array to be two elements")
}
return nil
}
type XRateData struct {
Rate json.Number `json:"rate"`
CCY string `json:"ccy"`
}
type BalanceData struct {
// TODO
}
type EventData struct {
// TODO
}
type SyncData struct {
Token string `json:"Token"`
}
var streamSnapshot = []byte(
`{
"ts": 1496244373.04,
"data":[
["xrate", {"rate":1.2916,"ccy":"USD"}],
["balance",
{
"open_stake":["GBP", 0.0],
"balance":["GBP", 0.0]
}
],
["event",
{
"competition_id":"545",
"ir_status":"pre_event",
"start_time":"2017-09-10T17:00:00+00:00",
"competition_name":"USA NFL",
"event_id":"2017-09-10,21617,21635",
"home":"Buffalo Bills",
"away":"New York Jets",
"sport":"af",
"competition_country":"US"
}
],
["sync", {"Token":"eb1c57132d004f8d8fb967c076921fac"}]
]
}`)
func main() {
var sm StreamMessage
if err := json.Unmarshal(streamSnapshot, &sm); err != nil {
panic(err)
}
fmt.Println(sm)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论