dpp78272 2015-09-02 06:34
浏览 39
已采纳

取消编组可能会或可能不会返回数组的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.

  • 写回答

2条回答 默认 最新

  • donglang6656 2015-09-02 09:27
    关注

    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 content 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:

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效