如何使用键值结构数组解组 JSON,其中键没有 json 标记
How to unmarshal JSON with array of key-value structs where key is does not have json tag
我在解组以下内容时遇到问题 json:
{
"input-1": [
"S",
15.0,
"some1",
[
[
1111111.357,
"QQ",
"Toronto"
]
]
],
"input-2": [
"EE",
90.1,
"some2",
[
[
55555550.705,
"RR",
"Kuala Lumpur"
],
[
22233330.134,
"OO",
"Bogota"
]
]
],
"input-3": [
"UU",
87.0,
"some99",
[
[
8800221.500,
"LL",
"Lagos"
]
]
]
}
我对应的代码是这样的:
package main
import (
"fmt"
"encoding/json"
"os"
"io/ioutil"
)
type InputC struct {
Type string
SomeFloat float64
CorrespondingPerson string
Desc []Under
}
type Under struct {
IDCity float64
CityType string
CityName string
}
func main() {
f, err := os.OpenFile("data.json", os.O_RDONLY, 0755)
if err != nil {
fmt.Printf("Error opening file: %v\n", err)
}
b, err := ioutil.ReadAll(f)
if err != nil {
fmt.Printf("Error reading file: %v\n", err)
}
inputs:= map[string]InputC{}
err = json.Unmarshal(b, &inputs)
if err != nil {
fmt.Printf("Error Unmarshalling file: %v\n", err)
}
for k, v := range(inputs) {
fmt.Printf("%v\n",v.Desc[0].IDCIty)
}
}
我从这段代码收到的响应是:
Error Unmarshalling file: json: cannot unmarshal array into Go value of type main.InputC panic: runtime error: index out of range
之后我将代码更改为:
inputs:= []InputC{}
但仍然出现错误:
Error Unmarshalling file: json: cannot unmarshal object into Go value of type []main.InputC
很明显我遗漏了一些东西,但我不知道如何从我拥有的 JSON 中提取信息。
如果在自定义结构上实现 json.Unmarshaler
接口并使用 []json.RawMessage
临时保存各个数组元素的值,则可以避免使用 []interface{}
。请记住,下面的解决方案在很大程度上依赖于要保证的数组值的数量和顺序。
type InputC struct {
Type string
SomeFloat float64
CorrespondingPerson string
Desc []Under
}
func (c *InputC) UnmarshalJSON(data []byte) error {
var s []json.RawMessage
if err := json.Unmarshal(data, &s); err != nil {
return err
}
if len(s) != 4 {
return errors.New("something's off")
}
dest := []interface{}{&c.Type, &c.SomeFloat, &c.CorrespondingPerson, &c.Desc}
for i := 0; i < len(s); i++ {
if err := json.Unmarshal(s[i], dest[i]); err != nil {
return err
}
}
return nil
}
type Under struct {
IDCity float64
CityType string
CityName string
}
func (u *Under) UnmarshalJSON(data []byte) error {
var s []json.RawMessage
if err := json.Unmarshal(data, &s); err != nil {
return err
}
if len(s) != 3 {
return errors.New("something's off")
}
dest := []interface{}{&u.IDCity, &u.CityType, &u.CityName}
for i := 0; i < len(s); i++ {
if err := json.Unmarshal(s[i], dest[i]); err != nil {
return err
}
}
return nil
}
https://play.golang.com/p/qpnvETC18rp
(请注意,在 playground 中打印的浮点数只是看起来 不同,因为这就是包 fmt
在使用 %v
动词时默认打印浮点数的方式. 例如这个 fmt.Printf("%v", 1111111.357)
输出 1.111111357e+06
.)
我在解组以下内容时遇到问题 json:
{
"input-1": [
"S",
15.0,
"some1",
[
[
1111111.357,
"QQ",
"Toronto"
]
]
],
"input-2": [
"EE",
90.1,
"some2",
[
[
55555550.705,
"RR",
"Kuala Lumpur"
],
[
22233330.134,
"OO",
"Bogota"
]
]
],
"input-3": [
"UU",
87.0,
"some99",
[
[
8800221.500,
"LL",
"Lagos"
]
]
]
}
我对应的代码是这样的:
package main
import (
"fmt"
"encoding/json"
"os"
"io/ioutil"
)
type InputC struct {
Type string
SomeFloat float64
CorrespondingPerson string
Desc []Under
}
type Under struct {
IDCity float64
CityType string
CityName string
}
func main() {
f, err := os.OpenFile("data.json", os.O_RDONLY, 0755)
if err != nil {
fmt.Printf("Error opening file: %v\n", err)
}
b, err := ioutil.ReadAll(f)
if err != nil {
fmt.Printf("Error reading file: %v\n", err)
}
inputs:= map[string]InputC{}
err = json.Unmarshal(b, &inputs)
if err != nil {
fmt.Printf("Error Unmarshalling file: %v\n", err)
}
for k, v := range(inputs) {
fmt.Printf("%v\n",v.Desc[0].IDCIty)
}
}
我从这段代码收到的响应是:
Error Unmarshalling file: json: cannot unmarshal array into Go value of type main.InputC panic: runtime error: index out of range
之后我将代码更改为:
inputs:= []InputC{}
但仍然出现错误:
Error Unmarshalling file: json: cannot unmarshal object into Go value of type []main.InputC
很明显我遗漏了一些东西,但我不知道如何从我拥有的 JSON 中提取信息。
如果在自定义结构上实现 json.Unmarshaler
接口并使用 []json.RawMessage
临时保存各个数组元素的值,则可以避免使用 []interface{}
。请记住,下面的解决方案在很大程度上依赖于要保证的数组值的数量和顺序。
type InputC struct {
Type string
SomeFloat float64
CorrespondingPerson string
Desc []Under
}
func (c *InputC) UnmarshalJSON(data []byte) error {
var s []json.RawMessage
if err := json.Unmarshal(data, &s); err != nil {
return err
}
if len(s) != 4 {
return errors.New("something's off")
}
dest := []interface{}{&c.Type, &c.SomeFloat, &c.CorrespondingPerson, &c.Desc}
for i := 0; i < len(s); i++ {
if err := json.Unmarshal(s[i], dest[i]); err != nil {
return err
}
}
return nil
}
type Under struct {
IDCity float64
CityType string
CityName string
}
func (u *Under) UnmarshalJSON(data []byte) error {
var s []json.RawMessage
if err := json.Unmarshal(data, &s); err != nil {
return err
}
if len(s) != 3 {
return errors.New("something's off")
}
dest := []interface{}{&u.IDCity, &u.CityType, &u.CityName}
for i := 0; i < len(s); i++ {
if err := json.Unmarshal(s[i], dest[i]); err != nil {
return err
}
}
return nil
}
https://play.golang.com/p/qpnvETC18rp
(请注意,在 playground 中打印的浮点数只是看起来 不同,因为这就是包 fmt
在使用 %v
动词时默认打印浮点数的方式. 例如这个 fmt.Printf("%v", 1111111.357)
输出 1.111111357e+06
.)