试图找到一种简单的方法来编组/分解为以下结构
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]接口并使用大量的反射测试..但这是漫长的尝试。
有想法吗?
亲切的问候
有很多方法可以构造它,但是最简单的技术归结为实现json.Unmarshaler和检查数据类型。您可以最少地解析json字节,通常只是第一个字符,或者您可以尝试解组每种类型并返回成功的类型。
json.Unmarshaler
我们将在此处使用后一种技术,并将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