一尘不染

去json解组选项

go

试图找到一种简单的方法来编组/分解为以下结构

type Resource struct {
    Data []ResourceData `json:"data"`
}
type ResourceData struct {
    Id string  `json:"id"`
    Type string  `json:"type"`
    Attributes map[string]interface{} `json:"attributes"`
    Relationships map[string]Resource `json:"relationships"`
}
r := Resource{}
json.Unmarshal(body, &r)

这在以下情况下很好:

body = `{"data":[{"id":"1","type":"blah"}]}`

但是我也需要它来回应:

body = `{"data":{"id":"1","type":"blah"}}` //notice no slice

我可以做一个单独的类型

type ResourceSingle struct {
    Data ResourceData `json:"data"`
}

但是,这意味着需要复制我附加到资源的所有功能,这是可能的。但是,在执行它之前,我需要先找出要解组的类型,再加上关系部分,每个类型都可能包含data:[]
{}或data {},所以这个主意不会工作。

或者我可以使用

map[string]*json.RawMessage
//or
type Resource struct {
    Data *json.RawMessage `json:"data"`
}

但是仍然,当以json形式时,我如何知道它是提供正确结构以解组的切片还是节点?

我的最后一招是将umarshal映射到map [string]接口并使用大量的反射测试..但这是漫长的尝试。

有想法吗?

亲切的问候


阅读 250

收藏
2020-07-02

共1个答案

一尘不染

有很多方法可以构造它,但是最简单的技术归结为实现json.Unmarshaler和检查数据类型。您可以最少地解析json字节,通常只是第一个字符,或者您可以尝试解组每种类型并返回成功的类型。

我们将在此处使用后一种技术,并将ResourceData插入切片中,而不管传入数据的格式如何,因此我们始终可以以相同的方式对其进行操作:

type Resource struct {
    Data []ResourceData
}

func (r *Resource) UnmarshalJSON(b []byte) error {
    // this gives us a temporary location to unmarshal into
    m := struct {
        DataSlice struct {
            Data []ResourceData `json:"data"`
        }
        DataStruct struct {
            Data ResourceData `json:"data"`
        }
    }{}

    // try to unmarshal the data with a slice
    err := json.Unmarshal(b, &m.DataSlice)
    if err == nil {
        log.Println("got slice")
        r.Data = m.DataSlice.Data
        return nil
    } else if err, ok := err.(*json.UnmarshalTypeError); !ok {
        // something besides a type error occurred
        return err
    }

    // try to unmarshal the data with a struct
    err = json.Unmarshal(b, &m.DataStruct)
    if err != nil {
        return err
    }
    log.Println("got struct")

    r.Data = append(r.Data, m.DataStruct.Data)
    return nil
}

http://play.golang.org/p/YIPeYv4AfT

2020-07-02