Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.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
Arrays 解码go中的嵌套json对象_Arrays_Json_Go_Nested - Fatal编程技术网

Arrays 解码go中的嵌套json对象

Arrays 解码go中的嵌套json对象,arrays,json,go,nested,Arrays,Json,Go,Nested,我找到了一些关于如何在go中解码json嵌套对象的帖子,我尝试将答案应用到我的问题中,但我只找到了部分解决方案 我的json文件如下所示: { "user":{ "gender":"male", "age":"21-30", "id":"80b1ea88-19d7-24e8-52cc-65cf6fb9b380" }, "trials":{ "0":{"index":0,"word":"WORD 1","Time":3000,"keyboard":true,

我找到了一些关于如何在go中解码json嵌套对象的帖子,我尝试将答案应用到我的问题中,但我只找到了部分解决方案

我的json文件如下所示:

{
"user":{
    "gender":"male",
    "age":"21-30",
    "id":"80b1ea88-19d7-24e8-52cc-65cf6fb9b380"
    },
"trials":{
    "0":{"index":0,"word":"WORD 1","Time":3000,"keyboard":true,"train":true,"type":"A"},
    "1":{"index":1,"word":"WORD 2","Time":3000,"keyboard":true,"train":true,"type":"A"},
    },
"answers":{
    "training":[
        {"ans":0,"RT":null,"gtAns":"WORD 1","correct":0},
        {"ans":0,"RT":null,"gtAns":"WORD 2","correct":0}
        ],
    "test":[
        {"ans":0,"RT":null,"gtAns":true,"correct":0},
        {"ans":0,"RT":null,"gtAns":true,"correct":0}
        ]
    }
}
基本上,我需要解析其中的信息并将它们保存到go结构中。使用下面的代码,我成功地提取了用户信息,但对我来说太复杂了,要将同样的内容应用到包含两个数组(每个数组包含100多个条目)的“answers”字段并不容易。下面是我现在使用的代码:

type userDetails struct {
    Id     string `json:"id"`
    Age    string `json:"age"`
    Gender string `json:"gender"`
}

type jsonRawData map[string]interface {
}

func getJsonContent(r *http.Request) ( userDetails) {
    defer r.Body.Close()
    jsonBody, err := ioutil.ReadAll(r.Body)
    var userDataCurr userDetails
    if err != nil {
        log.Printf("Couldn't read request body: %s", err)
    } else {
        var f jsonRawData
        err := json.Unmarshal(jsonBody, &f)
        if err != nil {
            log.Printf("Error unmashalling: %s", err)
        } else {
            user := f["user"].(map[string]interface{})
            userDataCurr.Id = user["id"].(string)
            userDataCurr.Gender = user["gender"].(string)
            userDataCurr.Age = user["age"].(string)
        }
    }
    return userDataCurr
}

有什么建议吗?非常感谢

使用
接口{}
而不是利用
编码/json
所提供的功能,这是一种艰难的做法

我会这样做(注意,我假设“gtAns”字段的类型有错误,我将其设置为布尔值,您没有提供足够的信息来知道如何处理“RT”字段):

当然,如果您想重用这些子类型,您可以将它们从“Whatever”类型拉到它们自己的命名类型中


另外,请注意使用了
json.Decoder
,而不是提前读取所有数据。通常尽量避免使用
ioutil.ReadAll
,除非您真的需要同时使用所有数据。

使用
接口{}
而不是利用
编码/json
所提供的功能,这是一种艰难的做法

我会这样做(注意,我假设“gtAns”字段的类型有错误,我将其设置为布尔值,您没有提供足够的信息来知道如何处理“RT”字段):

当然,如果您想重用这些子类型,您可以将它们从“Whatever”类型拉到它们自己的命名类型中


另外,请注意使用了
json.Decoder
,而不是提前读取所有数据。通常尽量避免使用
ioutil.ReadAll
,除非您真的需要同时使用所有数据。

使用
接口{}
而不是利用
编码/json
所提供的功能,这是一种艰难的做法

我会这样做(注意,我假设“gtAns”字段的类型有错误,我将其设置为布尔值,您没有提供足够的信息来知道如何处理“RT”字段):

当然,如果您想重用这些子类型,您可以将它们从“Whatever”类型拉到它们自己的命名类型中


另外,请注意使用了
json.Decoder
,而不是提前读取所有数据。通常尽量避免使用
ioutil.ReadAll
,除非您真的需要同时使用所有数据。

使用
接口{}
而不是利用
编码/json
所提供的功能,这是一种艰难的做法

我会这样做(注意,我假设“gtAns”字段的类型有错误,我将其设置为布尔值,您没有提供足够的信息来知道如何处理“RT”字段):

当然,如果您想重用这些子类型,您可以将它们从“Whatever”类型拉到它们自己的命名类型中


另外,请注意使用了
json.Decoder
,而不是提前读取所有数据。通常尽量避免使用
ioutil.ReadAll
,除非您真的需要同时使用所有数据。

谢谢您的回答,Dave!实际上,使用Whatever结构可以帮助我解决这个问题。关于ioutil.ReadAll,我尝试直接使用r.Body,但没有成功。您建议在r.Body上使用io.Reader吗?@Dede http.Response的
Body
字段是
io.Reader
。是的,如我所示,通过json.Decoder使用它。除非您需要请求的其他字段/方法,否则最好将
getJsonContent
函数的参数更改为
io.Reader
(就像我对
fromJSON
;或者可能是
io.ReadCloser
;在前者中,将其留给调用方关闭请求体)。这使它更加灵活(例如,您可以将存储的JSON的
*os.File
strings.Reader
传递给它进行测试)。谢谢,我实际上成功地做到了您使用
x,err:=fromJSON(r.Body)
所说的一切。顺便说一句,为了清楚起见,RT是
time.Duration
,gtAnswer(地面真相答案)是
string
。再次感谢汉克斯的回答,戴夫!实际上,使用Whatever结构可以帮助我解决这个问题。关于ioutil.ReadAll,我尝试直接使用r.Body,但没有成功。您建议在r.Body上使用io.Reader吗?@Dede http.Response的
Body
字段是
io.Reader
。是的,如我所示,通过json.Decoder使用它。除非您需要请求的其他字段/方法,否则最好将
getJsonContent
函数的参数更改为
io.Reader
(就像我对
fromJSON
;或者可能是
io.ReadCloser
;在前者中,将其留给调用方关闭请求体)。这使它更加灵活(例如,您可以将存储的JSON的
*os.File
strings.Reader
传递给它进行测试)。谢谢,我实际上成功地做到了您使用
x,err:=fromJSON(r.Body)
所说的一切。顺便说一句,为了清楚起见,RT是
time.Duration
,gtAnswer(地面真相答案)是
string
。再次感谢汉克斯的回答,戴夫!实际上,使用Whatever结构可以帮助我解决这个问题。关于ioutil.ReadAll,我尝试直接使用r.Body,但没有成功。您建议在r.Body上使用io.Reader吗?@Dede http.Response的
Body
字段是
io.Reader
。是的,如我所示,通过json.Decoder使用它。除非您需要请求的其他字段/方法,否则最好将
getJsonContent
函数的参数更改为
package main

import (
        "encoding/json"
        "fmt"
        "io"
        "log"
        "strconv"
        "strings"
)

const input = `{
"user":{
    "gender":"male",
    "age":"21-30",
    "id":"80b1ea88-19d7-24e8-52cc-65cf6fb9b380"
    },
"trials":{
    "0":{"index":0,"word":"WORD 1","Time":3000,"keyboard":true,"train":true,"type":"A"},
    "1":{"index":1,"word":"WORD 2","Time":3000,"keyboard":true,"train":true,"type":"A"}
    },
"answers":{
    "training":[
        {"ans":0,"RT":null,"gtAns":true,"correct":0},
        {"ans":0,"RT":null,"gtAns":true,"correct":0}
        ],
    "test":[
        {"ans":0,"RT":null,"gtAns":true,"correct":0},
        {"ans":0,"RT":null,"gtAns":true,"correct":0}
        ]
    }
}`

type Whatever struct {
        User struct {
                Gender Gender   `json:"gender"`
                Age    Range    `json:"age"`
                ID     IDString `json:"id"`
        } `json:"user"`
        Trials map[string]struct {
                Index int    `json:"index"`
                Word  string `json:"word"`
                Time  int    // should this be a time.Duration?
                Train bool   `json:"train"`
                Type  string `json:"type"`
        } `json:"trials"`
        Answers map[string][]struct {
                Answer    int             `json:"ans"`
                RT        json.RawMessage // ??? what type is this
                GotAnswer bool            `json:"gtAns"`
                Correct   int             `json:"correct"`
        } `json:"answers"`
}

// Using some custom types to show custom marshalling:

type IDString string // TODO custom unmarshal and format/error checking

type Gender int

const (
        Male Gender = iota
        Female
)

func (g *Gender) UnmarshalJSON(b []byte) error {
        var s string
        err := json.Unmarshal(b, &s)
        if err != nil {
                return err
        }
        switch strings.ToLower(s) {
        case "male":
                *g = Male
        case "female":
                *g = Female
        default:
                return fmt.Errorf("invalid gender %q", s)
        }
        return nil
}
func (g Gender) MarshalJSON() ([]byte, error) {
        switch g {
        case Male:
                return []byte(`"male"`), nil
        case Female:
                return []byte(`"female"`), nil
        default:
                return nil, fmt.Errorf("invalid gender %v", g)
        }
}

type Range struct{ Min, Max int }

func (r *Range) UnmarshalJSON(b []byte) error {
        // XXX could be improved
        _, err := fmt.Sscanf(string(b), `"%d-%d"`, &r.Min, &r.Max)
        return err
}
func (r Range) MarshalJSON() ([]byte, error) {
        return []byte(fmt.Sprintf(`"%d-%d"`, r.Min, r.Max)), nil
        // Or:
        b := make([]byte, 0, 8)
        b = append(b, '"')
        b = strconv.AppendInt(b, int64(r.Min), 10)
        b = append(b, '-')
        b = strconv.AppendInt(b, int64(r.Max), 10)
        b = append(b, '"')
        return b, nil
}

func fromJSON(r io.Reader) (Whatever, error) {
        var x Whatever
        dec := json.NewDecoder(r)
        err := dec.Decode(&x)
        return x, err
}

func main() {
        // Use http.Get or whatever to get an io.Reader,
        // (e.g. response.Body).
        // For playground, substitute a fixed string
        r := strings.NewReader(input)

        // If you actually had a string or []byte:
        //     var x Whatever
        //     err := json.Unmarshal([]byte(input), &x)

        x, err := fromJSON(r)
        if err != nil {
                log.Fatal(err)
        }
        fmt.Println(x)
        fmt.Printf("%+v\n", x)

        b, err := json.MarshalIndent(x, "", "  ")
        if err != nil {
                log.Fatal(err)
        }
        fmt.Printf("Re-marshalled: %s\n", b)

}