解组可能或不可以返回数组的JSON? [英] Unmarshalling a JSON that may or may not return an array?

查看:101
本文介绍了解组可能或不可以返回数组的JSON?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从第三方网站(家庭电力使用情况)中检索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:

这篇关于解组可能或不可以返回数组的JSON?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆