英文:
Unmarshall JSON with multiple value types and arbitrary number of keys
问题
我正在尝试读取以下形式的JSON:
{
string: int,
string: string,
string: MyStruct,
string: MyStruct,
...
string: MyStruct,
}
例如:
{
"status": 200,
"message": "一些很酷的文本",
"coolKeyA": {
"name": "尤达",
"age": 900
},
"CoolKeyB": {
"name": "马哈拉勒勒",
"age": 895
},
"CoolKeyC": {
"name": "王子",
"age": 57
},
}
期望的结果是获得一个map[string]MyStruct
的映射。其中"CoolKeyX"键的数量是弹性的或任意的,但其他键是静态的,例如status和message。
由于JSON中的值是不同类型的,我尝试将它们解析到一个空的map[string]interface{}
中。然后目标是循环遍历键,并提取感兴趣的键,并将map[string]interface{string: string, string: int}
的键转换为MyStruct。
scaryAcceptAll := map[string]interface{}{}
if err = json.Unmarshal(byteArray, &scaryAcceptAll); err != nil {
log.Printf("error: %v", err)
return err
}
for k,v := range scaryAcceptAll {
if (k == "val0" ) || (k == "val1") {
continue
}
desiredMap[k] = models.MyStruct{Name: v["name"], Age: v["age"]}
}
这给我带来了以下错误:NonIndexableOperand: invalid operation: cannot index v (variable of type interface{})
我知道解组JSON的基本思想是创建一个与JSON类似的结构体并使用它,但由于我不知道确切的键的数量或"CoolKey"键实际上是什么(因为它是一个包含哈希值"000ab8f26d"的字符串),所以我不知道该怎么做。我知道接口有点像一个万能类型,但我不确定如何从中提取我想要的数据。
英文:
I'm attempting to read a JSON with the following form
{
string: int,
string: string,
string: MyStruct,
string: MyStruct,
...
string: MyStruct,
}
For example
{
"status": 200,
"message": "some cool text",
"coolKeyA": {
"name": "yoda",
"age": 900
},
"CoolKeyB": {
"name": "Mahalalel",
"age": 895
},
"CoolKeyC": {
"name": "Prince",
"age": 57
},
}
The desired outcome is to get a map of map[string]MyStruct
. There are an elastic or arbitrary number of "CoolKeyX" keys but the other keys are static, e.g., status and message.
Since the values in the JSON are different types I tried to reach them in to a blank map[string]interface{}
. Then the goal is to loop through the keys and pluck out they keys of interest and convert the keys of map[string]inferface{string: string, string: int}
to MyStruct.
scaryAcceptAll := map[string]interface{}{}
if err = json.Unmarshal(byteArray, &scaryAcceptAll); err != nil {
log.Printf("error: %v", err)
return err
}
for k,v := range scaryAcceptAll {
if (k == "val0" ) || (k == "val1") {
continue
}
desiredMap[k] = models.MyStruct{Name: v["name"], Age: v["age"]}
}
Which gives me the following error: NonIndexableOperand: invalid operation: cannot index v (variable of type interface{})
I know the basic idea of unmarshalling JSONs is to create a struct that looks like the json and use that but since I don't know the exact number of keys or what the "CoolKey" key really is (because it's a string containing a hash "000ab8f26d") I didn't know how. I know interfaces are sort of a catch all but then I'm not sure how to pull my desired data out of it.
答案1
得分: 1
一种方法是实现一个自定义的json.Unmarshaler
:
type Obj struct {
Status int
Message string
CoolKeys map[string]Person
}
type Person struct {
Name string
Age int
}
func (o *Obj) UnmarshalJSON(data []byte) error {
// 首先,将对象反序列化为原始 JSON 的映射
var m map[string]json.RawMessage
if err := json.Unmarshal(data, &m); err != nil {
return err
}
// 接下来,反序列化状态和消息字段,以及不属于“CoolKey”组的任何其他字段
if err := json.Unmarshal(m["status"], &o.Status); err != nil {
return err
}
delete(m, "status") // 确保从映射中删除该字段
if err := json.Unmarshal(m["message"], &o.Message); err != nil {
return err
}
delete(m, "message") // 确保从映射中删除该字段
// 最后,反序列化映射的其余内容
o.CoolKeys = make(map[string]Person)
for k, v := range m {
var p Person
if err := json.Unmarshal(v, &p); err != nil {
return err
}
o.CoolKeys[k] = p
}
return nil
}
https://go.dev/play/p/s4YCmve-pnz
英文:
One approach would be implement a custom json.Unmarshaler
:
type Obj struct {
Status int
Message string
CoolKeys map[string]Person
}
type Person struct {
Name string
Age int
}
func (o *Obj) UnmarshalJSON(data []byte) error {
// first, unmarshal the object into a map of raw json
var m map[string]json.RawMessage
if err := json.Unmarshal(data, &m); err != nil {
return err
}
// next, unmarshal the status and message fields, and any
// other fields that don't belong to the "CoolKey" group
if err := json.Unmarshal(m["status"], &o.Status); err != nil {
return err
}
delete(m, "status") // make sure to delete it from the map
if err := json.Unmarshal(m["message"], &o.Message); err != nil {
return err
}
delete(m, "message") // make sure to delete it from the map
// finally, unmarshal the rest of the map's content
o.CoolKeys = make(map[string]Person)
for k, v := range m {
var p Person
if err := json.Unmarshal(v, &p); err != nil {
return err
}
o.CoolKeys[k] = p
}
return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论