Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在GO中反序列化非标准json_Json_Go_Deserialization - Fatal编程技术网

在GO中反序列化非标准json

在GO中反序列化非标准json,json,go,deserialization,Json,Go,Deserialization,我正在编写一个简单的应用程序,它向一个API发出请求,该API返回类型为的异构JSON { "results": [ [123, "Zho's Mask", 10586], [345, "Ravaging Superior Studded Coat", 58] ] } 最终,我希望能够使用结果响应中的特定索引。例如,我希望能够得到“Zho的面具”,或者价格:10586。这是我正在使用的API GO JSON博客

我正在编写一个简单的应用程序,它向一个API发出请求,该API返回类型为的异构JSON

{
  "results": [
    [123, "Zho's Mask", 10586],
    [345, "Ravaging Superior Studded Coat", 58]
  ]
}
最终,我希望能够使用结果响应中的特定索引。例如,我希望能够得到“Zho的面具”,或者价格:10586。这是我正在使用的API

GO JSON博客中的大多数示例都引用了不包含嵌套数组的更简单或直接的JSON

从我读到的内容来看,因为我知道JSON响应的一般外观,所以我可以创建一个GO结构并将其解组到该结构的实例中。但是,我无法为此作业创建正确的结构

这是我当前创建适当结构的尝试

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

// {"results":[[123,"Zho's Mask",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: ", err, "\n")
    }

}
这是解组错误:

Unmarshal error: json: cannot unmarshal array into Go struct field Equipment.Results of type main.ResArray
最后,这里是我目前对这个期望的GO结构的方法的灵感

类型重新排列结构{

但它不是一个结构,它是一个切片

但它不是字符串,有时是字符串,有时是数字

实现这一点的简单方法是将您的类型定义为

type Equipment struct {
    Results [][]interface{}
}
也就是说,结果中包含一片……某物。你可以在类型之间命名,但这不是必需的。例如,
e.Results[0][1]。(string)
将是
“Zho的掩码”

更好的方法是通过提供自定义的
解组JSON
来实现接口,如下所示:

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, got %T", arr[1])

    }

    sell, ok := arr[2].(float64)
    if !ok {
        return fmt.Errorf("expected float64 for Item.Sell, got %T", arr[2])
    }
    i.Sell = int(sell)
    return nil
}

请记住,这些类型与您向API请求的字段的确切列表相结合-如果您更改这些字段,则必须更改类型以及从数组中加载它的unmarshal函数。

使用
接口{}
而不是
string
或编写自己的解组函数。这正是我想要的答案和解释!
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, got %T", arr[1])

    }

    sell, ok := arr[2].(float64)
    if !ok {
        return fmt.Errorf("expected float64 for Item.Sell, got %T", arr[2])
    }
    i.Sell = int(sell)
    return nil
}