用 golang 解码 PubNub 消息 JSON
Decoding PubNub messages with golang JSON
我一直在尝试解析来自 PubNub 的 JSON 消息,但没有成功:
type PubNubMessage struct {
body []string
}
[[{"text":"hey"}],"1231212412423235","channelName"]
json: cannot unmarshal array into Go value of type main.PubNubMessage
有没有人知道如何在 golang 中解码如此复杂的类型?
您可以在 PubNubMessage
上定义 UnmarshalJSON
以提供自定义 JSON 反序列化。您可能应该根据自己的目的稍微调整一下,但一般的想法是您只需将此 json 数组解组为一个切片,然后从中获取所有必要的部分。
简短的回答是,您不能直接将 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)
你的json是一个异构数组。您至少可以将 PubNubMessage
定义为
type PubNubMessage []interface{}
然后使用类型断言访问数据 text:= (message[0].([]interface {})[0].(map[string]interface {}))["text"].(string)
工作示例 https://play.golang.org/p/xhwbE2ora1
或type PubNubMessage []json.RawMessage
和json.Unmarshal(jsonBlob, &message)
之后分别为每个和平'json.Unmarshal(message[0], structured.text)'
https://play.golang.org/p/TJ0DfiweGo
使用 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]
我一直在尝试解析来自 PubNub 的 JSON 消息,但没有成功:
type PubNubMessage struct {
body []string
}
[[{"text":"hey"}],"1231212412423235","channelName"]
json: cannot unmarshal array into Go value of type main.PubNubMessage
有没有人知道如何在 golang 中解码如此复杂的类型?
您可以在 PubNubMessage
上定义 UnmarshalJSON
以提供自定义 JSON 反序列化。您可能应该根据自己的目的稍微调整一下,但一般的想法是您只需将此 json 数组解组为一个切片,然后从中获取所有必要的部分。
简短的回答是,您不能直接将 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)
你的json是一个异构数组。您至少可以将 PubNubMessage
定义为
type PubNubMessage []interface{}
然后使用类型断言访问数据 text:= (message[0].([]interface {})[0].(map[string]interface {}))["text"].(string)
工作示例 https://play.golang.org/p/xhwbE2ora1
或type PubNubMessage []json.RawMessage
和json.Unmarshal(jsonBlob, &message)
之后分别为每个和平'json.Unmarshal(message[0], structured.text)'
https://play.golang.org/p/TJ0DfiweGo
使用 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]