在 Go 中部分 JSON 解组为地图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11066946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:23:49  来源:igfitidea点击:

Partly JSON unmarshal into a map in Go

jsonmapgo

提问by ANisus

My websocket server will receive and unmarshal JSON data. This data will always be wrapped in an object with key/value pairs. The key-string will act as value identifier, telling the Go server what kind of value it is. By knowing what type of value, I can then proceed to JSON unmarshal the value into the correct type of struct.

我的 websocket 服务器将接收和解组 JSON 数据。此数据将始终包含在具有键/值对的对象中。key-string 将作为值标识符,告诉 Go 服务器它是什么类型的值。通过知道什么类型的值,我可以继续 JSON 将值解组为正确类型的结构。

Each json-object might contain multiple key/value pairs.

每个 json-object 可能包含多个键/值对。

Example JSON:

示例 JSON:

{
    "sendMsg":{"user":"ANisus","msg":"Trying to send a message"},
    "say":"Hello"
}

Is there any easy way using the "encoding/json"package to do this?

有没有什么简单的方法可以使用这个"encoding/json"包来做到这一点?

package main

import (
    "encoding/json"
    "fmt"
)

// the struct for the value of a "sendMsg"-command
type sendMsg struct {
    user string
    msg  string
}
// The type for the value of a "say"-command
type say string

func main(){
    data := []byte(`{"sendMsg":{"user":"ANisus","msg":"Trying to send a message"},"say":"Hello"}`)

    // This won't work because json.MapObject([]byte) doesn't exist
    objmap, err := json.MapObject(data)

    // This is what I wish the objmap to contain
    //var objmap = map[string][]byte {
    //  "sendMsg": []byte(`{"user":"ANisus","msg":"Trying to send a message"}`),
    //  "say": []byte(`"hello"`),
    //}
    fmt.Printf("%v", objmap)
}

Thanks for any kind of suggestion/help!

感谢您的任何建议/帮助!

回答by Stephen Weinberg

This can be accomplished by Unmarshaling into a map[string]json.RawMessage.

这可以通过将map[string]json.RawMessage.

var objmap map[string]json.RawMessage
err := json.Unmarshal(data, &objmap)

To further parse sendMsg, you could then do something like:

要进一步解析sendMsg,您可以执行以下操作:

var s sendMsg
err = json.Unmarshal(objmap["sendMsg"], &s)

For say, you can do the same thing and unmarshal into a string:

对于say,您可以执行相同的操作并将其解组为字符串:

var str string
err = json.Unmarshal(objmap["say"], &str)


EDIT:Keep in mind you will also need to export the variables in your sendMsg struct to unmarshal correctly. So your struct definition would be:

编辑:请记住,您还需要导出 sendMsg 结构中的变量以正确解组。所以你的结构定义将是:

type sendMsg struct {
    User string
    Msg  string
}

Example: https://play.golang.org/p/OrIjvqIsi4-

示例:https: //play.golang.org/p/OrIjvqIsi4-

回答by Jun Xie

Further to Stephen Weinberg's answer, I have since implemented a handy tool called iojson, which helps to populate data to an existing object easily as well as encoding the existing object to a JSON string. A iojson middleware is also provided to work with other middlewares. More examples can be found at https://github.com/junhsieh/iojson

继斯蒂芬温伯格的回答之后,我实现了一个名为iojson的方便工具,它有助于轻松地将数据填充到现有对象以及将现有对象编码为 JSON 字符串。还提供了 iojson 中间件以与其他中间件一起使用。更多例子可以在https://github.com/junhsieh/iojson找到

Example:

例子:

func main() {
    jsonStr := `{"Status":true,"ErrArr":[],"ObjArr":[{"Name":"My luxury car","ItemArr":[{"Name":"Bag"},{"Name":"Pen"}]}],"ObjMap":{}}`

    car := NewCar()

    i := iojson.NewIOJSON()

    if err := i.Decode(strings.NewReader(jsonStr)); err != nil {
        fmt.Printf("err: %s\n", err.Error())
    }

    // populating data to a live car object.
    if v, err := i.GetObjFromArr(0, car); err != nil {
        fmt.Printf("err: %s\n", err.Error())
    } else {
        fmt.Printf("car (original): %s\n", car.GetName())
        fmt.Printf("car (returned): %s\n", v.(*Car).GetName())

        for k, item := range car.ItemArr {
            fmt.Printf("ItemArr[%d] of car (original): %s\n", k, item.GetName())
        }

        for k, item := range v.(*Car).ItemArr {
            fmt.Printf("ItemArr[%d] of car (returned): %s\n", k, item.GetName())
        }
    }
}

Sample output:

示例输出:

car (original): My luxury car
car (returned): My luxury car
ItemArr[0] of car (original): Bag
ItemArr[1] of car (original): Pen
ItemArr[0] of car (returned): Bag
ItemArr[1] of car (returned): Pen

回答by Taban Cosmos

Here is an elegant way to do similar thing. But why do partly JSON unmarshal? That doesn't make sense.

这是一个优雅的方式来做类似的事情。但是为什么要部分 JSON 解组呢?那没有意义。

  1. Create your structs for the Chat.
  2. Decode json to the Struct.
  3. Now you can access everything in Struct/Object easily.
  1. 为聊天创建您的结构。
  2. 将 json 解码为 Struct。
  3. 现在您可以轻松访问 Struct/Object 中的所有内容。

Look below at the working code. Copy and paste it.

看看下面的工作代码。复制并粘贴它。

import (
   "bytes"
   "encoding/json" // Encoding and Decoding Package
   "fmt"
 )

var messeging = `{
"say":"Hello",
"sendMsg":{
    "user":"ANisus",
    "msg":"Trying to send a message"
   }
}`

type SendMsg struct {
   User string `json:"user"`
   Msg  string `json:"msg"`
}

 type Chat struct {
   Say     string   `json:"say"`
   SendMsg *SendMsg `json:"sendMsg"`
}

func main() {
  /** Clean way to solve Json Decoding in Go */
  /** Excellent solution */

   var chat Chat
   r := bytes.NewReader([]byte(messeging))
   chatErr := json.NewDecoder(r).Decode(&chat)
   errHandler(chatErr)
   fmt.Println(chat.Say)
   fmt.Println(chat.SendMsg.User)
   fmt.Println(chat.SendMsg.Msg)

}

 func errHandler(err error) {
   if err != nil {
     fmt.Println(err)
     return
   }
 }

Go playground

去游乐场