如何解决在GO中反序列化非标准json
我正在编写一个简单的应用程序,该应用程序向API发送请求,该API返回类型不同的JSON
{
"results": [
[123,"Zho's Mask",10586],[345,"Ravaging Superior Studded Coat",58]
]
}
最终,我希望能够使用结果响应中的特定索引。例如,我希望能够获得“ Zho's Mask”或价格:10586。这是我正在使用的API GW2TP。
GO JSON博客中的大多数示例都引用了不包含嵌套数组的更简单或更直接的JSON。
根据我的阅读,由于我了解JSON响应的一般外观,因此我可以制作一个GO结构并将其解组为该结构的实例。但是,我无法为此工作创建正确的结构。
这是我当前尝试创建合适的结构
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
// {"results":[[123,3532]]}
type Equipment struct {
Results []ResArray
}
type ResArray struct {
Medium []LastArray
}
type LastArray struct {
Info string
}
func main() {
res,err := http.Get("http://api.gw2tp.com/1/items?ids=123&fields=name,sell")
if err != nil {
log.Fatal(err)
}
var equipment Equipment
data,err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Print("ReadAll Error: ",err,"\n")
}
err = json.Unmarshal(data,&equipment)
if err != nil {
fmt.Print("Unmarshal error: ","\n")
}
}
这是解组错误:
Unmarshal error: json: cannot unmarshal array into Go struct field Equipment.Results of type main.ResArray
最后,这是我目前对这种所需的GO结构的使用方法的灵感 JSON in Golang an Introduction。
解决方法
类型ResArray结构{
但这不是结构,而是切片!
type LastArray struct { Info string }
但这不是字符串,有时是字符串,有时是数字。
执行此操作的简单方法是将您的类型定义为
type Equipment struct {
Results [][]interface{}
}
表示结果包含一片……东西。您可以命名中间类型,但这不是必需的。然后例如e.Results[0][1].(string)
将是"Zho's Mask"
。
更好的方法是通过提供自定义UnmarshalJSON
来实现Unmarshaler接口,如下所示:
type Equipment struct {
Results []Item
}
type Item struct {
ID int
Name string
Sell int
}
func (i *Item) UnmarshalJSON(b []byte) error {
// We're deserializing into a struct,but in JSON it's a mixed-type array.
var arr []interface{}
err := json.Unmarshal(b,&arr)
if err != nil {
return fmt.Errorf("unmarshal Item underlying array: %w",err)
}
if len(arr) != 3 {
return fmt.Errorf("Item underlying array should be 3 elements,got %d",len(arr))
}
// JSON numbers will become float64 when loaded into interface{} but we want int
id,ok := arr[0].(float64)
if !ok {
return fmt.Errorf("expected float64 for Item.ID,got %T",arr[0])
}
i.ID = int(id)
i.Name,ok = arr[1].(string)
if !ok {
return fmt.Errorf("expected string for Item.Name,arr[1])
}
sell,ok := arr[2].(float64)
if !ok {
return fmt.Errorf("expected float64 for Item.Sell,arr[2])
}
i.Sell = int(sell)
return nil
}
请记住,这些类型与您向API请求的字段的确切列表相关联-如果更改此类型,则必须更改类型和加载它的解组函数从数组中获取。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。