简体   繁体   English

Unmarshal JSON与列表中的不同类型一起使用

[英]Unmarshal JSON in go with different types in a list

I have trouble unmarschaling a JSON contruct: 我无法解开JSON构造:

{
  "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: 我也可以参考Result [1]索引:

[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". 什么方法将是“最好的”。

One option would be to unmarshal the top level thing into a slice of json.RawMessage initially. 一种选择是最初将顶级事物解组成一片json.RawMessage

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. 如果它是一个对象,则将其解组到InfoMap头结构中,如果它是一个数组,则将其解组为Code结构的一个片段。

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)
}

(I will not point out how horrific it is this JSON struct, but as always: sXXt happens) (我不会指出它是多么可怕这个JSON结构,但一如既往:sXXt发生)

You can convert your struct like this, by using a cycle of JSON Marshal / Unmarshal. 您可以使用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 . 操场上测试它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM