Unmarshal JSON in go with different types in a list

独自空忆成欢 提交于 2019-12-01 21:01:32

问题


I have trouble unmarschaling a JSON contruct:

{
  "id": 10,
  "result": [
    {
      "bundled": true,
      "type": "RM-J1100"
    },
    [
      {
        "name": "PowerOff",
        "value": "AAAAAQAAAAEAAAAvAw=="
      },
      {
        "name": "Input",
        "value": "AAAAAQAAAAEAAAAlAw=="
      }
    ]
  ]
}

I actually need the second slice item from the result.

My current attempt is

type Codes struct {
    Id     int32      `json:"id"`
    Result []interface{} `json:"result"`
}

type ResultList struct {
    Info  InfoMap
    Codes []Code
}

type InfoMap struct {
    Bundled bool   `json:"bundled"`
    Type    string `json:"type"`
}

type Code struct {
    Name  string `json:"name"`
    Value string `json:"value"`
}

the output is like:

{10 {{false } []}}

but I also tried to use this:

type Codes struct {
    Id     int32      `json:"id"`
    Result []interface{} `json:"result"`
}

the output is okay:

{10 [map[type:RM-J1100 bundled:true] [map[name:PowerOff value:AAAAAQAAAAEAAAAvAw==] map[name:Input value:AAAAAQAAAAEAAAAlAw==]]]}

I can also reference the Result[1] index:

[map[name:PowerOff value:AAAAAQAAAAEAAAAvAw==] map[name:Input value:AAAAAQAAAAEAAAAlAw==]]

But I fail to convert the interface type to any other Type which would match. Can anybody tell me how to do interface conversion. And what approach would be the "best".


回答1:


One option would be to unmarshal the top level thing into a slice of json.RawMessage initially.

Then loop through the members, and look at the first character of each one. If it is an object, unmarshal that into your InfoMap header struct, and if it is an array, unmarshal it into a slice of the Code struct.

Or if it is predictable enough, just unmarshal the first member to the one struct and the second to a slice.

I made a playground example of this approach.

type Response struct {
    ID        int               `json:"id"`
    RawResult []json.RawMessage `json:"result"`
    Header    *Header           `json:"-"`
    Values    []*Value          `json:"-"`
}

type Header struct {
    Bundled bool   `json:"bundled"`
    Type    string `json:"type"`
}

type Value struct {
    Name  string `json:"name"`
    Value string `json:"value"`
}

func main() {
    //error checks ommitted
    resp := &Response{}
    json.Unmarshal(rawJ, resp)
    resp.Header = &Header{}
    json.Unmarshal(resp.RawResult[0], resp.Header)
    resp.Values = []*Value{}
    json.Unmarshal(resp.RawResult[1], &resp.Values)
}



回答2:


(I will not point out how horrific it is this JSON struct, but as always: sXXt happens)

You can convert your struct like this, by using a cycle of JSON Marshal / Unmarshal. Code follows:

package main

import (
    "encoding/json"
    "log"
)

const (
    inputJSON = `{
  "id": 10,
  "result": [
    {
      "bundled": true,
      "type": "RM-J1100"
    },
    [
      {
        "name": "PowerOff",
        "value": "AAAAAQAAAAEAAAAvAw=="
      },
      {
        "name": "Input",
        "value": "AAAAAQAAAAEAAAAlAw=="
      }
    ]
  ]
}`
)

type Codes struct {
    Id     int32          `json:"id"`
    Result [2]interface{} `json:"result"`
}

type Result struct {
    Info  InfoMap
    Codes []Code
}

type InfoMap struct {
    Bundled bool   `json:"bundled"`
    Type    string `json:"type"`
}

type Code struct {
    Name  string `json:"name"`
    Value string `json:"value"`
}

func main() {
    newCodes := &Codes{}
    err := json.Unmarshal([]byte(inputJSON), newCodes)
    if err != nil {
        log.Fatal(err)
    }

    // Prints the whole object
    log.Println(newCodes)

    // Prints the Result array (!)
    log.Println(newCodes.Result)

    if len(newCodes.Result) != 2 {
        log.Fatal("Invalid Result struct")
    }

    // Marshal and Unmarshal data to obtain the code list
    byteCodeList, _ := json.Marshal(newCodes.Result[1])

    codeList := make([]Code, 0)

    err = json.Unmarshal(byteCodeList, &codeList)
    if err != nil {
        log.Fatal("Invalid Code list")
    }

    // Prints the codeList
    log.Println(codeList)
}

Test it on playground.



来源:https://stackoverflow.com/questions/43796509/unmarshal-json-in-go-with-different-types-in-a-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!