如何在不解组两次的情况下在 golang 中解析 JSON

Bob*_*sta 3 json go

我有一个网络套接字连接,它在 JSON 对象中发送不同类型的消息,我想将内容解组为一些已知的结构。为此,我认为我应该执行以下操作:

步骤 1) 将 JSON 解组为通用 map[string]interface{}

第 2 步)找到我要找的钥匙

第 3 步)尝试将值转换为我的一种类型(失败)

步骤 3 替代)json 编组此值并将其解组到我已知的结构中

如果我尝试使用 myStruct, ok := value.(myType)它会失败,但如果我 json.marshal(value) 然后 json.unmarshal 到 myStruct,它工作得很好。这就是我应该这样做的方式吗?转到 json-> map[string]interface{} -> json -> myStruct 对我来说似乎是多余的。

示例代码:

https://play.golang.org/p/to_0Id_ja9

package main

import (
    "encoding/json"
    "fmt"
)

type Ping struct {
    Ping string `json:"ping"`
}

type Ack struct {
    Messages []Message `json:"messages"`
}

type Message string

func main() {
    testJSON := []byte(`{"ack":{"messages":["Hi there","Hi again"]}}`)
    var myAck = Ack{}
    var myMap map[string]interface{}
    err := json.Unmarshal(testJSON, &myMap)
    if err != nil {
        fmt.Println("error unmarshalling: ", err)
    }
    for k, v := range myMap {
        fmt.Printf("key: %s, value: %s \n", k, v)

        switch k {
        case "ping":
            fmt.Println(k, " is a ping", v)
        case "ack":
            fmt.Println(k, " is an ack containing a message list")
            ackjson, err := json.Marshal(v)
            if err != nil {
                fmt.Println("marshal error: ", err)
            }
            err = json.Unmarshal(ackjson, &myAck)
            if err != nil {
                fmt.Println("unmarshal error", err)
            } else {
                fmt.Println("New ack object: ", myAck)
            }
        default:
            fmt.Printf("%s is of a type (%T) I don't know how to handle", k, v)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ANi*_*sus 5

一种解决方案是通过将值解组为一个json.RawMessage而不是一个来部分解组数据interface{}

var myMap map[string]json.RawMessage
Run Code Online (Sandbox Code Playgroud)

稍后在仍然需要的 switch 中,您不需要编组。做就是了:

err = json.Unmarshal(v, &myAck)
Run Code Online (Sandbox Code Playgroud)

游乐场: https : //play.golang.org/p/NHd3uH5e7z


Mob*_*ius 0

您将需要创建一个包含您可能收到的所有密钥的结构,然后解组一次,最后根据哪些密钥nil您可以决定获得哪种数据包。

下面的示例显示了此行为:https ://play.golang.org/p/aFG6M0SPJs

package main

import (
  "encoding/json"
  "fmt"
  "strings"
)


type Ack struct {
  Messages []string `json:"messages"`
}

type Packet struct {
  Ack  * Ack    `json:"ack"`
  Ping * string `json:"ping"`
}

func runTest(testJSON []byte) {
  var p = Packet{}
  err := json.Unmarshal(testJSON, &p)
  if err != nil {
    fmt.Println("error unmarshalling: ", err)
  }
  if (p.Ack != nil) {
    fmt.Println("Got ACK: ", strings.Join(p.Ack.Messages, ", "));
  } else if (p.Ping != nil){
          fmt.Println("Got PING");
  }
}

func main() {
  tests := [][]byte{
    []byte(`{"ack":{"messages":["Hi there","Hi again"]}}`),
    []byte(`{"ping": "Are you there?"}`),
  }
  for _, test := range tests {
    runTest(test)
  }

}
Run Code Online (Sandbox Code Playgroud)