解组可能或不可以返回数组的JSON? [英] Unmarshalling a JSON that may or may not return an array?
问题描述
我从第三方网站(家庭电力使用情况)中检索JSON,并且根据我对网站的要求,返回的JSON可能不是阵列。例如,如果我要求我的智能电表清单,我会得到这个结果(结果截断,由于大尺寸):
{gwrcmds:{gwrcmd:{gcmd:SPA_UserGetSmartMeterList,gdata:{gip:{version:1...
其中 gwrcmd 是一个单一元素。
请求用电过去半小时,我得到这个:
{gwrcmds:{gwrcmd:[{ gcmd:DeviceGetChart,gdata:{gip:{version:1...
看看 gwrcmd 现在是一个数组吗?
在我的Go应用程序中,我有一个看起来像这样的结构在版本下面还有更多的子结构和属性:
类型响应struct {
Gwrcmds struct {
Gwrcmd struct {
Gcmd string
Gdata struct {
Gip struct {
Version字符串
如果 gwrcmd
是一个数组, code> Gwrcmd 需要是 [] struct {}
,但如果不是,它只是一个普通的旧的 struct {}
问题在于 json.Unmarshal
错误,如果JSON有一个数组,并且该结构没有切片(反之亦然)。
我需要创建第二个结构,它复制第一个结构(除非用 [] struct {}
来代替),还是有更好的方法来做到这一点?我想到了一些与接口有关的东西,但是我还没有真正触及它们,所以我不能100%确定它们。
通常,只要您的JSON值为未知类型,就会使用 json.RawMessage
来获取它,查看它并将其正确解组为相应的类型。一个简单的例子:
//这里的A可以是对象,也可以是JSON数组对象。
类型响应struct {
RawAWrapper struct {
RawA json.RawMessage`json:a`
}
AA`json: - `
as [] A`json: - `
}
type A struct {
B string
}
func( r * Response)UnmarshalJSON(b [] byte)错误{
if err:= json.Unmarshal(b,& r.RawAWrapper);如果r.RawAWrapper.RawA [0] =='['{
return json.Unmarshal(r.RawAWrapper.RawA, & r.As)
}
return json.Unmarshal(r.RawAWrapper.RawA,& rA)
}
游乐场: http://play.golang。 org / p / 2d_OrGltDu 。
猜测基于第一个字节的竞争对我来说看起来不太健壮。通常你会在你的JSON中有一些线索(如同一级别的长度
或类型
字段)作为动态的)告诉你是否有对象或数组。
另见:
I'm retrieving JSON from a third party website (home electricity usage), and depending on what I've requested from the site, the JSON returned may or may not be an array. For example, if I request a list of my smart meters, I get this (results truncated, due to large size):
{"gwrcmds":{"gwrcmd":{"gcmd":"SPA_UserGetSmartMeterList","gdata":{"gip":{"version":"1"...
Where gwrcmd is a single element.
But if I request electricity usage for the last half hour, I get this:
{"gwrcmds":{"gwrcmd":[{"gcmd":"DeviceGetChart","gdata":{"gip":{"version":"1" ...
See how gwrcmd is now an array?
Within my Go app, I have a struct that looks like this (again, truncated, as it goes on for a while. There's more sub-structs and properties beneath "Version":
type Response struct {
Gwrcmds struct {
Gwrcmd struct {
Gcmd string
Gdata struct {
Gip struct {
Version string
If gwrcmd
is an array, Gwrcmd
needs to be a []struct { }
, but if it's not, it's just a regular old struct { }
The problem is that json.Unmarshal
just returns an error if the JSON has an array and the struct does not have a slice (or vice versa).
Would I need to create a second struct that duplicates the first one (except with a []struct { }
instead), or is there a better way to do it? I thought of something with interfaces, but I haven't really touched those yet, so I'm not 100% sure on them.
Usually, whenever you have a JSON value of unknown type, you will use json.RawMessage
to get it, peek into it, and unmarshal it correctly into the corresponding type. A simplified example:
// 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.
Guessing the contend based on the first byte doesn't seem too robust to me though. Usually you'll have some sort of a clue in your JSON (like a length
or type
field on the same level as the dynamic one) that tells you whether you have an object or an array.
See also:
- How can you decode multiple message types with golang websockets?
- Partly JSON unmarshal into a map in Go
这篇关于解组可能或不可以返回数组的JSON?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!