我正在从第三方网站(家庭用电)检索 JSON,根据我从该网站请求的内容,返回的 JSON 可能是也可能不是数组。例如,如果我请求我的智能电表列表,我会得到这个(由于尺寸大,结果被截断):
{"gwrcmds":{"gwrcmd":{"gcmd":"SPA_UserGetSmartMeterList","gdata":{"gip":{"version":"1"...
其中 gwrcmd 是单个元素。
但如果我请求过去半小时的用电量,我会得到:
{"gwrcmds":{"gwrcmd":[{"gcmd":"DeviceGetChart","gdata":{"gip":{"version":"1" ...
看到 gwrcmd 现在是一个数组了吗?
在我的 Go 应用程序中,我有一个看起来像这样的结构(同样,被截断了,因为它持续了一段时间。“Version”下面有更多的子结构和属性:
type Response struct {
Gwrcmds struct {
Gwrcmd struct {
Gcmd string
Gdata struct {
Gip struct {
Version string
如果 gwrcmd
是一个数组,Gwrcmd
需要是一个 []struct { }
,但如果不是,它只是一个常规的旧的结构{}
问题是如果 JSON 有一个数组而结构没有 slice (反之亦然),json.Unmarshal
只会返回一个错误。
我是否需要创建第二个结构来复制第一个结构(除了使用 []struct { }
代替),还是有更好的方法来做到这一点?我想到了一些带有接口(interface)的东西,但我还没有真正接触过它们,所以我不能 100% 确定它们。
最佳答案
通常,当你有一个未知类型的 JSON 值时,你会使用 json.RawMessage
获取它,查看它,并将其正确解码为相应的类型。一个简化的例子:
// The A here can be either an object, or a JSON array of objects.
type Response struct {
RawAWrapper struct {
RawA json.RawMessage `json:"a"`
}
A A `json:"-"`
As []A `json:"-"`
}
type A struct {
B string
}
func (r *Response) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(b, &r.RawAWrapper); err != nil {
return err
}
if r.RawAWrapper.RawA[0] == '[' {
return json.Unmarshal(r.RawAWrapper.RawA, &r.As)
}
return json.Unmarshal(r.RawAWrapper.RawA, &r.A)
}
Playground :http://play.golang.org/p/2d_OrGltDu .
不过,根据第一个字节猜测内容对我来说似乎不太可靠。通常,您的 JSON 中会有某种线索(如 length
或 type
字段,与动态字段处于同一级别)告诉您是否有对象或数组。
另见:
关于json - 解码可能会或可能不会返回数组的 JSON?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32346117/