如何在 Go 中解码 JSON 其中 returns 多个元素作为类型数组和单个元素作为类型
How to decode JSON in Go which returns multiple elements as array of type and individual elements as type
我正在使用发送 JSON 数据的 API。问题是单个元素的数组显示为单个值。例如,考虑以下 JSON:
{ "names": ["Alice","Bob"] }
API 将其作为数组发送。但是当 names
字段只有一个元素时,API 发送这个:
{ "names": "Alice" }
这就是我通常在 Go 中解码响应的方式:
type Response struct {
Names []string `json:"names"`
}
// later
d := &Response{}
_ = json.NewDecoder(resp).Decode(d) // resp would be a http.Response.Body containing the problematic JSON
Go 正确解码了第一个 JSON。但是,在解码第二个 JSON 后,对象包含一个空数组。
我无法控制 API,所以我必须解决这个问题。我如何在 Go 中正确解码此 JSON,以便 Names
切片包含单个元素?谢谢您的帮助。
您必须将其解码为 interface{}
,然后使用类型断言来检查基础类型是切片还是字符串。
type Response struct {
Names interface{} `json:"names"`
}
然后在解码为 d
之后,您将执行如下操作:
slice, ok := d.Names.([]interface{})
if ok {
// it was a slice. use it.
} else {
// it wasn't a slice - so expect it to be a string
// and use that, etc.
}
您可以实现 json.Unmarshaler
接口并让它检查 [
或 "
的第 0 个原始字节以分别确定它是数组还是字符串:
type StringSlice []string
func (ss *StringSlice) UnmarshalJSON(data []byte) error {
if data[0] == '[' {
return json.Unmarshal(data, (*[]string)(ss))
} else if data[0] == '"' {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
*ss = append(*ss, s)
}
return nil
}
使用 json.RawMessage
作为类型。 RawMessage 只是延迟了部分消息的解码,所以我们可以稍后自己做。
type Response struct {
NamesRaw json.RawMessage `json:"names"`
Names []string
}
首先,解码响应,然后使用 json.Unmarshal
解码 json.RawMessage
x := &Response{}
_ = json.NewDecoder(resp).Decode(x);
x.Names = DecodeName(x.NamesRaw)
DecodeName
用于解码NameRaw
数据
func DecodeName(nameRaw json.RawMessage) (data []string) {
var s string
if err := json.Unmarshal(nameRaw, &s); err == nil {
v := []string{s}
return v
}
var sn []string
if err := json.Unmarshal(nameRaw, &sn); err == nil {
return sn
}
return
}
我正在使用发送 JSON 数据的 API。问题是单个元素的数组显示为单个值。例如,考虑以下 JSON:
{ "names": ["Alice","Bob"] }
API 将其作为数组发送。但是当 names
字段只有一个元素时,API 发送这个:
{ "names": "Alice" }
这就是我通常在 Go 中解码响应的方式:
type Response struct {
Names []string `json:"names"`
}
// later
d := &Response{}
_ = json.NewDecoder(resp).Decode(d) // resp would be a http.Response.Body containing the problematic JSON
Go 正确解码了第一个 JSON。但是,在解码第二个 JSON 后,对象包含一个空数组。
我无法控制 API,所以我必须解决这个问题。我如何在 Go 中正确解码此 JSON,以便 Names
切片包含单个元素?谢谢您的帮助。
您必须将其解码为 interface{}
,然后使用类型断言来检查基础类型是切片还是字符串。
type Response struct {
Names interface{} `json:"names"`
}
然后在解码为 d
之后,您将执行如下操作:
slice, ok := d.Names.([]interface{})
if ok {
// it was a slice. use it.
} else {
// it wasn't a slice - so expect it to be a string
// and use that, etc.
}
您可以实现 json.Unmarshaler
接口并让它检查 [
或 "
的第 0 个原始字节以分别确定它是数组还是字符串:
type StringSlice []string
func (ss *StringSlice) UnmarshalJSON(data []byte) error {
if data[0] == '[' {
return json.Unmarshal(data, (*[]string)(ss))
} else if data[0] == '"' {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
*ss = append(*ss, s)
}
return nil
}
使用 json.RawMessage
作为类型。 RawMessage 只是延迟了部分消息的解码,所以我们可以稍后自己做。
type Response struct {
NamesRaw json.RawMessage `json:"names"`
Names []string
}
首先,解码响应,然后使用 json.Unmarshal
解码 json.RawMessage
x := &Response{}
_ = json.NewDecoder(resp).Decode(x);
x.Names = DecodeName(x.NamesRaw)
DecodeName
用于解码NameRaw
数据
func DecodeName(nameRaw json.RawMessage) (data []string) {
var s string
if err := json.Unmarshal(nameRaw, &s); err == nil {
v := []string{s}
return v
}
var sn []string
if err := json.Unmarshal(nameRaw, &sn); err == nil {
return sn
}
return
}