Unmarshal JSON 进入列表中的不同类型
Unmarshal JSON in go with different types in a list
我在解组 JSON 结构时遇到问题:
{
"id": 10,
"result": [
{
"bundled": true,
"type": "RM-J1100"
},
[
{
"name": "PowerOff",
"value": "AAAAAQAAAAEAAAAvAw=="
},
{
"name": "Input",
"value": "AAAAAQAAAAEAAAAlAw=="
}
]
]
}
我实际上需要结果中的第二个切片项。
我目前的尝试是
type Codes struct {
Id int32 `json:"id"`
Result []interface{} `json:"result"`
}
type ResultList struct {
Info InfoMap
Codes []Code
}
type InfoMap struct {
Bundled bool `json:"bundled"`
Type string `json:"type"`
}
type Code struct {
Name string `json:"name"`
Value string `json:"value"`
}
输出如下:
{10 {{false } []}}
不过我也试过用这个:
type Codes struct {
Id int32 `json:"id"`
Result []interface{} `json:"result"`
}
输出正常:
{10 [map[type:RM-J1100 bundled:true] [map[name:PowerOff value:AAAAAQAAAAEAAAAvAw==] map[name:Input value:AAAAAQAAAAEAAAAlAw==]]]}
我也可以参考结果[1]索引:
[map[name:PowerOff value:AAAAAQAAAAEAAAAvAw==] map[name:Input value:AAAAAQAAAAEAAAAlAw==]]
但是我无法将接口类型转换为任何其他匹配的类型。谁能告诉我如何进行接口转换。 "best".
是什么方法?
一个选择是最初将顶级事物解组为 json.RawMessage
的一部分。
然后遍历成员,查看每个成员的第一个字符。如果它是一个对象,将它解组到你的 InfoMap
头结构中,如果它是一个数组,将它解组到 Code
结构的一个片段中。
或者如果它足够可预测,只需将第一个成员解组为一个结构,将第二个成员解组为一个切片。
我对这种方法进行了playground example。
type Response struct {
ID int `json:"id"`
RawResult []json.RawMessage `json:"result"`
Header *Header `json:"-"`
Values []*Value `json:"-"`
}
type Header struct {
Bundled bool `json:"bundled"`
Type string `json:"type"`
}
type Value struct {
Name string `json:"name"`
Value string `json:"value"`
}
func main() {
//error checks ommitted
resp := &Response{}
json.Unmarshal(rawJ, resp)
resp.Header = &Header{}
json.Unmarshal(resp.RawResult[0], resp.Header)
resp.Values = []*Value{}
json.Unmarshal(resp.RawResult[1], &resp.Values)
}
(我不会指出这个 JSON 结构有多可怕,但一如既往:sXXt 会发生)
您可以像这样转换您的结构,方法是使用 JSON 编组/解组循环。代码如下:
package main
import (
"encoding/json"
"log"
)
const (
inputJSON = `{
"id": 10,
"result": [
{
"bundled": true,
"type": "RM-J1100"
},
[
{
"name": "PowerOff",
"value": "AAAAAQAAAAEAAAAvAw=="
},
{
"name": "Input",
"value": "AAAAAQAAAAEAAAAlAw=="
}
]
]
}`
)
type Codes struct {
Id int32 `json:"id"`
Result [2]interface{} `json:"result"`
}
type Result struct {
Info InfoMap
Codes []Code
}
type InfoMap struct {
Bundled bool `json:"bundled"`
Type string `json:"type"`
}
type Code struct {
Name string `json:"name"`
Value string `json:"value"`
}
func main() {
newCodes := &Codes{}
err := json.Unmarshal([]byte(inputJSON), newCodes)
if err != nil {
log.Fatal(err)
}
// Prints the whole object
log.Println(newCodes)
// Prints the Result array (!)
log.Println(newCodes.Result)
if len(newCodes.Result) != 2 {
log.Fatal("Invalid Result struct")
}
// Marshal and Unmarshal data to obtain the code list
byteCodeList, _ := json.Marshal(newCodes.Result[1])
codeList := make([]Code, 0)
err = json.Unmarshal(byteCodeList, &codeList)
if err != nil {
log.Fatal("Invalid Code list")
}
// Prints the codeList
log.Println(codeList)
}
在 playground.
上测试
我在解组 JSON 结构时遇到问题:
{
"id": 10,
"result": [
{
"bundled": true,
"type": "RM-J1100"
},
[
{
"name": "PowerOff",
"value": "AAAAAQAAAAEAAAAvAw=="
},
{
"name": "Input",
"value": "AAAAAQAAAAEAAAAlAw=="
}
]
]
}
我实际上需要结果中的第二个切片项。
我目前的尝试是
type Codes struct {
Id int32 `json:"id"`
Result []interface{} `json:"result"`
}
type ResultList struct {
Info InfoMap
Codes []Code
}
type InfoMap struct {
Bundled bool `json:"bundled"`
Type string `json:"type"`
}
type Code struct {
Name string `json:"name"`
Value string `json:"value"`
}
输出如下:
{10 {{false } []}}
不过我也试过用这个:
type Codes struct {
Id int32 `json:"id"`
Result []interface{} `json:"result"`
}
输出正常:
{10 [map[type:RM-J1100 bundled:true] [map[name:PowerOff value:AAAAAQAAAAEAAAAvAw==] map[name:Input value:AAAAAQAAAAEAAAAlAw==]]]}
我也可以参考结果[1]索引:
[map[name:PowerOff value:AAAAAQAAAAEAAAAvAw==] map[name:Input value:AAAAAQAAAAEAAAAlAw==]]
但是我无法将接口类型转换为任何其他匹配的类型。谁能告诉我如何进行接口转换。 "best".
是什么方法?一个选择是最初将顶级事物解组为 json.RawMessage
的一部分。
然后遍历成员,查看每个成员的第一个字符。如果它是一个对象,将它解组到你的 InfoMap
头结构中,如果它是一个数组,将它解组到 Code
结构的一个片段中。
或者如果它足够可预测,只需将第一个成员解组为一个结构,将第二个成员解组为一个切片。
我对这种方法进行了playground example。
type Response struct {
ID int `json:"id"`
RawResult []json.RawMessage `json:"result"`
Header *Header `json:"-"`
Values []*Value `json:"-"`
}
type Header struct {
Bundled bool `json:"bundled"`
Type string `json:"type"`
}
type Value struct {
Name string `json:"name"`
Value string `json:"value"`
}
func main() {
//error checks ommitted
resp := &Response{}
json.Unmarshal(rawJ, resp)
resp.Header = &Header{}
json.Unmarshal(resp.RawResult[0], resp.Header)
resp.Values = []*Value{}
json.Unmarshal(resp.RawResult[1], &resp.Values)
}
(我不会指出这个 JSON 结构有多可怕,但一如既往:sXXt 会发生)
您可以像这样转换您的结构,方法是使用 JSON 编组/解组循环。代码如下:
package main
import (
"encoding/json"
"log"
)
const (
inputJSON = `{
"id": 10,
"result": [
{
"bundled": true,
"type": "RM-J1100"
},
[
{
"name": "PowerOff",
"value": "AAAAAQAAAAEAAAAvAw=="
},
{
"name": "Input",
"value": "AAAAAQAAAAEAAAAlAw=="
}
]
]
}`
)
type Codes struct {
Id int32 `json:"id"`
Result [2]interface{} `json:"result"`
}
type Result struct {
Info InfoMap
Codes []Code
}
type InfoMap struct {
Bundled bool `json:"bundled"`
Type string `json:"type"`
}
type Code struct {
Name string `json:"name"`
Value string `json:"value"`
}
func main() {
newCodes := &Codes{}
err := json.Unmarshal([]byte(inputJSON), newCodes)
if err != nil {
log.Fatal(err)
}
// Prints the whole object
log.Println(newCodes)
// Prints the Result array (!)
log.Println(newCodes.Result)
if len(newCodes.Result) != 2 {
log.Fatal("Invalid Result struct")
}
// Marshal and Unmarshal data to obtain the code list
byteCodeList, _ := json.Marshal(newCodes.Result[1])
codeList := make([]Code, 0)
err = json.Unmarshal(byteCodeList, &codeList)
if err != nil {
log.Fatal("Invalid Code list")
}
// Prints the codeList
log.Println(codeList)
}
在 playground.
上测试