在 Golang 中解组具有重叠字段的动态 JSON 数据

Unmarshalling Dynamic JSON Data With Overlapping Fields in Golang

抱歉,如果我发布的问题已经得到解答,但我似乎无法在这里找到任何类似的情况。我有一个 websocket 客户端,它接收具有重叠字段的动态 json 数据。字段重叠的事实使解组对我来说非常困难。

我有针对接收到的数据类型的结构,但我需要一种方法来检查 json 数据,然后再将其解组为特定结构。我希望接口可以充当临时持有者,然后我可以将接口与我想要解组的特定结构相匹配,但这似乎不可能,或者我只是不知道该怎么做关于它。以下是我正在接收的数据类型的一些示例以及与其一起使用的结构,以备不时之需。

response 1: {"connectionID":17973829270596587247,"event":"systemStatus","status":"online","version":"1.9.0"}
response 2: {"channelID":328,"channelName":"ohlc-5","event":"subscriptionStatus","pair":"XBT/USD","status":"subscribed","subscription":{"interval":5,"name":"ohlc"}}
response 3: [328,["1649576721.042916","1649577000.000000","42641.50000","42641.50000","42641.50000","42641.50000","42641.50000","0.00335101",2],"ohlc-5","XBT/USD"]
response 4: {"event":"heartbeat"}

structs below
import (
    "time"
    "encoding/json"
)

type ConnStatus struct {
    ConnectionID        uint64          `json:"connectionID"`
    Event               string          `json:"event"`
    Status              string          `json:"status"`
    Version             string          `json:"version"`
}

type HeartBeat struct {
    Event               string          `json:"event"`
}

type OHLCsuccess struct {
    ChannelID           int             `json:"channelID"`
    ChannelName         string          `json:"channelName"`
    Event               string          `json:"event"`
    Pair                string          `json:"pair"`
    Status              string          `json:"status"`
    Subscription        OHLC            `json:"subscription"`
}

type OHLC struct {
    Interval        int         `json:"interval"`
    Name            string      `json:"name"`
}

type OHLCUpdates struct {
    ChannelID           int
    OHLCArray           OHLCNewTrade
    ChannelName         string
    Pair                string
}

type OHLCNewTrade struct {
    StartTime           UnixTime
    EndTime             UnixTime
    Open                float64
    High                float64
    Low                 float64
    Close               float64
    VWAP                float64
    Volume              float64
    Count               int
}

type UnixTime struct {
    time.Time
}

func (u *UnixTime) UnmarshalJSON(d []byte) error {
    var ts int64
    err := json.Unmarshal(d, &ts)
    if err != nil {
        return err
    }
    u.Time = time.Unix(ts, 0).UTC()
    return nil
}

关于如何解决这个问题的任何想法?在此先感谢您的帮助!

你能控制不同的反应吗?如果是这样,要不要在顶层添加一个“类型”字段?

有关详细信息,请参阅 https://eagain.net/articles/go-dynamic-json/ 上的“如何将所有内容置于顶层”部分。

例如(未经测试):

func UnmarshalJSON(d []byte) error {
    var jsonValue map[string]interface{}
    err := json.Unmarshal(d, &jsonValue)

    if err != nil {
        return err
    }

    switch jsonValue["type"] {
    case 1:
        // unmarshal into struct type 1
    case 2:
        // unmarshal into struct type 2
    default:
        // throw err
    }

    // or if you don't have access to type:
    if jsonValue["connectionID"] != nil {
        // unmarshal into struct type 1
    }

    return nil
}

或者,您可以尝试(严格地)解组到每个结构中,直到您没有收到错误为止,例如类似于:

func DetermineStruct(d []byte) int {
    var connStatus *ConnStatus

    reader := bytes.NewReader(d)
    decoder := json.NewDecoder(reader)
    decoder.DisallowUnknownFields()

    err := decoder.Decode(connStatus)
    if err == nil {
        panic(err)
    }

    err = json.Unmarshal(d, &connStatus)
    if err == nil {
        return 1
    }

    var ohlcSuccess OHLCsuccess
    err = json.Unmarshal(d, &ohlcSuccess)
    if err == nil {
        return 2
    }
}