在go中解码嵌套的json对象

我找到了一些关于如何在 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 结构中。使用下面的代码,我设法提取了用户信息,但对我来说它看起来太复杂了,将同样的事情应用到“答案”字段并不容易,该字段包含 2 个数组,每个数组超过 100 个条目。这是我现在使用的代码:


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

}

有什么建议?非常感谢!


MYYA
浏览 266回答 1
1回答

Helenr

你通过使用interface{}而不是利用encoding/json给你的东西来做这件事。我会做这样的事情(注意我假设“gtAns”字段的类型有错误,我把它设为布尔值,你没有提供足够的信息来知道如何处理“RT”字段):package mainimport (        "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 checkingtype Gender intconst (        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)}Playground当然,如果您想重用这些子类型,您可以将它们从“Whatever”类型中提取到它们自己的命名类型中。另外,请注意使用 ajson.Decoder而不是提前读取所有数据。通常尽量避免使用 ,ioutil.ReadAll除非您真的需要一次获得所有数据。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go