Decoding PubNub messages with golang JSON

喜欢而已 提交于 2020-01-15 06:32:09

问题


I've been trying to parse this JSON message from PubNub without any luck:

type PubNubMessage struct {
    body []string
}

[[{"text":"hey"}],"1231212412423235","channelName"]
json: cannot unmarshal array into Go value of type main.PubNubMessage

Does anyone have an idea on how to decode such complex types in golang?


回答1:


The short answer is that you cannot directly unmarshal a JSON array of non-homogenous types (per your example) into a golang struct.

The long answer is that you should define an (m *PubNubMessage) UnmarshalJSON([]byte) error method for your PubNubMessage type which unmarshals the JSON string into an interface{} and then uses type assertions to ensure the expected format and populates the structure.

For example:

type TextMessage struct {
  Text string
}

type PubNubMessage struct {
  Messages []TextMessage
  Id       string
  Channel  string
}

func (pnm *PubNubMessage) UnmarshalJSON(bs []byte) error {
  var arr []interface{}
  err := json.Unmarshal(bs, &arr)
  if err != nil {
    return err
  }
  messages := arr[0].([]interface{}) // TODO: proper type check.
  pnm.Messages = make([]TextMessage, len(messages))
  for i, m := range messages {
    pnm.Messages[i].Text = m.(map[string]interface{})["text"].(string) // TODO: proper type check.
  }
  pnm.Id = arr[1].(string) // TODO: proper type check.
  pnm.Channel = arr[2].(string) // TODO: proper type check.
  return nil
}

  // ...
  jsonStr := `[[{"text":"hey"},{"text":"ok"}],"1231212412423235","channelName"]`
  message := PubNubMessage{}
  err := json.Unmarshal([]byte(jsonStr), &message)



回答2:


You can define UnmarshalJSON on your PubNubMessage to provide custom JSON deserialization. You probably should tweak this a little bit for your purposes, but the general idea is that you just unmarshal this json array into a slice, and then get all necessary parts from it.

Playground example here




回答3:


Your json is a heterogeneous array. You can at least define PubNubMessage as either

type PubNubMessage []interface{} and then access data with type assertions text:= (message[0].([]interface {})[0].(map[string]interface {}))["text"].(string) working example https://play.golang.org/p/xhwbE2ora1

or type PubNubMessage []json.RawMessage and after json.Unmarshal(jsonBlob, &message) do 'json.Unmarshal(message[0], structured.text)' for each peace separately
https://play.golang.org/p/TJ0DfiweGo




回答4:


It is easier to use alternative to encoding/json packages for parsing JSON arrays with values of distinct types. For instance, give a try to fastjson. It easily (and quickly) parses such arrays:

input := `[[{"text":"hey"}],"1231212412423235","channelName"]`

var p fastjson.Parser
v, err := p.Parse(input)
if err != nil {
    log.Fatal(err)
}
a := v.GetArray()
for _, vv := range a {
    switch vv.Type() {
    case fastjson.TypeArray:
        fmt.Printf("array %s\n", vv)
    case fastjson.TypeString:
        fmt.Printf("string %s\n", vv)
    }
}

Additionally fastjson provides handy functions for obtaining only the required fields from JSON:

// get v[0].text as Go byte slice
text := v.GetStringBytes("0", "text")

// get v[2]
channelName := v.Get("2")  // this is the same as v.GetArray()[2]


来源:https://stackoverflow.com/questions/29348262/decoding-pubnub-messages-with-golang-json

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!