【问题标题】:Decoding PubNub messages with golang JSON使用 golang JSON 解码 PubNub 消息
【发布时间】:2015-03-30 14:03:41
【问题描述】:

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

type PubNubMessage struct {
    body []string
}

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

有人知道如何在 golang 中解码如此复杂的类型吗?

【问题讨论】:

  • 请注意,示例文档的第一个元素不是字符串(如body []string 所要求的那样),而是带有键“text”的对象/结构数组...
  • 是的,但是我如何映射这样的结构?
  • 每个人都应该阅读这个:talks.golang.org/2015/json.slide#1

标签: json go pubnub


【解决方案1】:

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

长答案是您应该为您的 PubNubMessage 类型定义一个 (m *PubNubMessage) UnmarshalJSON([]byte) error method,它将 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)

【讨论】:

    【解决方案2】:

    您的 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

    【讨论】:

      【解决方案3】:

      您可以在 PubNubMessage 上定义 UnmarshalJSON 以提供自定义 JSON 反序列化。您可能应该根据您的目的稍微调整一下,但一般的想法是您只需将此 json 数组解组为一个切片,然后从中获取所有必要的部分。

      Playground example这里

      【讨论】:

        【解决方案4】:

        使用 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 %s\n", vv)
            case fastjson.TypeString:
                fmt.Printf("string %s\n", 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]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多