英文:
go json unmarshal options
问题
尝试找到一个简单的解决方案来将数据解析成以下结构:
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"}}` // 注意没有切片
我可以创建一个单独的类型:
type ResourceSingle struct {
Data ResourceData `json:"data"`
}
然而,这意味着我需要复制所有附加到resource
的函数,这是可能的。然而,我需要在执行之前找出要解析成哪种类型,而且当涉及到关系部分时,每个关系都可以包含data:[]
或data{}
,所以这个想法行不通。
另一种方法是使用:
map[string]*json.RawMessage
// 或者
type Resource struct {
Data *json.RawMessage `json:"data"`
}
但是,当以JSON形式存在时,我如何知道它是一个切片还是一个节点,以便提供正确的结构进行解析?
我最后的选择是将其解析为map[string]interface{}
,然后使用大量的反射测试...但这样非常冗长。
有什么想法吗?
谢谢,jJ
英文:
Trying to find a simple solution to marshaling/unmashaling into the following struct
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)
this is great if:
body = `{"data":[{"id":"1","type":"blah"}]}`
However I also need it to respond to:
body = `{"data":{"id":"1","type":"blah"}}` //notice no slice
I could make a separate type
type ResourceSingle struct {
Data ResourceData `json:"data"`
}
However, that would mean needing to duplicate all the functions I have attached to resource, which is possible. However, i would need to find out which type to unmarshal into before executing it, plus when it comes to the relationships part, each of those could contain data:[]{} or data{}, so that idea isn't going to work.
Alternatively I could use
map[string]*json.RawMessage
//or
type Resource struct {
Data *json.RawMessage `json:"data"`
}
but still, when in json form how do I know if it is a slice or a node to supply the correct struct to unmarshal into?
My last resort is to umarshal into map[string]interface and use lots of reflect testing .. but this is very long winded.
Ideas?
Kind regards, jJ
答案1
得分: 2
有多种方法可以对其进行结构化,但最简单的技术是实现json.Unmarshaler
,并检查数据的类型。你可以最小程度地解析JSON字节,通常只需解析第一个字符,或者尝试将其解组为每种类型并返回成功的类型。
在这里,我们将使用后一种技术,无论传入数据的格式如何,都将ResourceData插入到一个切片中,以便我们始终可以以相同的方式操作它:
type Resource struct {
Data []ResourceData
}
func (r *Resource) UnmarshalJSON(b []byte) error {
// 这给了我们一个临时位置来解组
m := struct {
DataSlice struct {
Data []ResourceData `json:"data"`
}
DataStruct struct {
Data ResourceData `json:"data"`
}
}{}
// 尝试使用切片解组数据
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 {
// 发生了除类型错误之外的其他错误
return err
}
// 尝试使用结构体解组数据
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
英文:
There's a number of ways to structure it, but the simplest technique comes down to implementing a json.Unmarshaler
, and inspecting the type of the data. You can minimally parse the json bytes, often just the first character, or you can try to unmarshal into each type and return the one that succeeds.
We'll use the latter technique here, and insert the ResourceData into a slice regardless of the incoming data's format, so we can always operate on it in the same manner:
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论