解析动态JSON

huangapple go评论93阅读模式
英文:

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)
}

https://play.golang.org/p/ktABS6z40m

huangapple
  • 本文由 发表于 2017年6月20日 18:13:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/44650198.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定