使用golang JSON解码PubNub消息



我一直在尝试从PubNub解析这个JSON消息,但没有任何运气:

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

有人知道如何在戈兰解码这种复杂的类型吗?

简单的答案是,您不能直接将非同质类型的JSON数组(根据您的示例)解组为golang结构。

详细的答案是,您应该为PubNubMessage类型定义一个(m *PubNubMessage) UnmarshalJSON([]byte) error方法,该方法将JSON字符串解组为interface{},然后使用类型断言来确保预期的格式并填充结构。

例如:

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)

json是一个异构数组。您至少可以将PubNubMessage定义为

type PubNubMessage []interface{},然后使用类型断言text:= (message[0].([]interface {})[0].(map[string]interface {}))["text"].(string)访问数据工作示例https://play.golang.org/p/xhwbE2ora1

type PubNubMessage []json.RawMessagejson.Unmarshal(jsonBlob, &message)之后分别为每个和平执行"json.Unmarshal(message[0],structured.text)"
https://play.golang.org/p/TJ0DfiweGo

您可以在PubNubMessage上定义UnmarshalJSON,以提供自定义的JSON反序列化。出于您的目的,您可能应该对此进行一点调整,但总体思路是,您只需将这个json数组分解为一个切片,然后从中获取所有必要的部分。

此处的游乐场示例

使用encoding/json包的替代方案来解析具有不同类型值的JSON数组更容易。例如,尝试使用fastjson。它可以轻松(快速)解析这样的数组:

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 %sn", vv)
    case fastjson.TypeString:
        fmt.Printf("string %sn", vv)
    }
}

此外,fastjson提供了方便的功能,可以从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]

最新更新