部分JSON解析为Go中的映射

huangapple go评论106阅读模式
英文:

Partly JSON unmarshal into a map in Go

问题

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.

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

Example 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?

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!

英文:

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.

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

Example 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?

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!

答案1

得分: 264

这可以通过将其解组为map[string]json.RawMessage来实现。

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

要进一步解析sendMsg,你可以这样做:

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

对于say,你可以做同样的事情并解组为字符串:

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

**编辑:**请记住,您还需要将sendMsg结构体中的变量导出以正确解组。因此,您的结构体定义应为:

type sendMsg struct {
    User string
    Msg  string
}

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

英文:

This can be accomplished by Unmarshaling into a 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:

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

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

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:

type sendMsg struct {
    User string
    Msg  string
}

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

答案2

得分: 5

这里有一种优雅的方法来完成类似的事情。但是为什么要部分解析JSON呢?这没有意义。

  1. 为聊天创建你的结构体。
  2. 将JSON解码为结构体。
  3. 现在你可以轻松地访问结构体/对象中的所有内容。

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

import (
	"bytes"
	"encoding/json" // 编码和解码包
	"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() {
	/** 清晰的解决Go中的JSON解码 */
	/** 优秀的解决方案 */

	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

英文:

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

  1. Create your structs for the Chat.
  2. Decode json to the Struct.
  3. Now you can access everything in Struct/Object easily.

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
1: https://play.golang.org/p/zWU3cuESqJn

答案3

得分: 2

根据Stephen Weinberg的回答,我已经实现了一个方便的工具叫做iojson,它可以帮助将数据填充到现有对象中,并将现有对象编码为JSON字符串。还提供了一个iojson中间件,可以与其他中间件一起使用。更多示例可以在[https://github.com/junhsieh/iojson][2]找到。

示例:

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

    // 将数据填充到现有的car对象中。
    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())
        }
    }
}

示例输出:

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

[2]: https://github.com/junhsieh/iojson "一个方便的工具,用于在golang中编写RESTful API。它使您能够通过统一的JSON格式在客户端和服务器之间交换数据。"

英文:

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][2]

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

[2]: https://github.com/junhsieh/iojson "A handy tool for writing RESTful API in golang. It enables you to exchange data between client and server through a uniform JSON format."

答案4

得分: 0

type HostData struct {
Username string json:"username"
Password string json:"password"
Secret string json:"secret"
}

func main() {
data := []byte(
{ "ynb": { "username": "userynb", "password": "pwdynb", "secret": "secterynb" }, "was":{ "username": "userwas", "password": "pwdwas", "secret": "secretwas" } })

var objmap map[string]json.RawMessage
err := json.Unmarshal(data, &objmap)
if err != nil {
    log.Fatal(err)
}

var hostDataMap map[string]HostData = make(map[string]HostData)
for key := range objmap {
    var hd HostData
    err = json.Unmarshal(objmap[key], &hd)
    if err != nil {
        log.Fatal(err)
        return
    }
    hostDataMap[key] = hd
}

fmt.Println(hostDataMap)

}

英文:

Simple flat json to map:
For example json:

{
 "was": {
  "username": "userwas",
  "password": "pwdwas",
  "secret": "secretwas"
 },
 "ynb": {
  "username": "userynb",
  "password": "pwdynb",
  "secret": "secterynb"
 }
}

Ok, create struct:

type HostData struct {
    Username string `json:"username"`
   	Password string `json:"password"`
    Secret   string `json:"secret"`
}

and main func:

func main() {
    // Example as []byte
	data := []byte(
		`{
		"ynb": {
			"username": "userynb",
			"password": "pwdynb",
			"secret": "secterynb"
		},
		"was":{
			"username": "userwas",
			"password": "pwdwas",
			"secret": "secretwas"
		}
    }`)

	var objmap map[string]json.RawMessage
	err := json.Unmarshal(data, &objmap)
	if err != nil {
		log.Fatal(err)
	}

	var hostDataMap map[string]HostData = make(map[string]HostData)
    // find keys and fill out the map
	for key := range objmap {
		var hd HostData
		err = json.Unmarshal(objmap[key], &hd)
		if err != nil {
			log.Fatal(err)
			return
		}
		hostDataMap[key] = hd
	}

    // Output map:
    fmt.Println(hostDataMap)
    // Output:
    // map[was:{userwas pwdwas secretwas} ynb:{userynb pwdynb secterynb}]
    / or if:
    //fmt.Println(hostDataMap["was"].Username)
    // Output: userwas
}

Full code with back map to json: https://go.dev/play/p/qocCW_rAnAL

huangapple
  • 本文由 发表于 2012年6月17日 04:51:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/11066946.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定