JSON không quản lý một phần vào bản đồ trong Go


98

Máy chủ websocket của tôi sẽ nhận và xử lý dữ liệu JSON. Dữ liệu này sẽ luôn được bao bọc trong một đối tượng với các cặp khóa / giá trị. Chuỗi khóa sẽ hoạt động như một mã định danh giá trị, cho máy chủ Go biết nó là loại giá trị nào. Bằng cách biết loại giá trị nào, sau đó tôi có thể tiến hành JSON bỏ quản lý giá trị thành loại cấu trúc chính xác.

Mỗi json-object có thể chứa nhiều cặp khóa / giá trị.

JSON mẫu:

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

Có cách nào dễ dàng sử dụng "encoding/json"gói để thực hiện việc này không?

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

Cảm ơn vì bất kỳ loại gợi ý / giúp đỡ!

Câu trả lời:


194

Điều này có thể được thực hiện bằng cách Unmarshaling thành a map[string]json.RawMessage.

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

Để phân tích cú pháp thêm sendMsg, sau đó bạn có thể làm điều gì đó như:

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

Đối với say, bạn có thể làm điều tương tự và không quản lý thành một chuỗi:

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

CHỈNH SỬA: Hãy nhớ rằng bạn cũng sẽ cần xuất các biến trong cấu trúc sendMsg của mình để bỏ quản lý một cách chính xác. Vì vậy, định nghĩa cấu trúc của bạn sẽ là:

type sendMsg struct {
    User string
    Msg  string
}

Ví dụ: https://play.golang.org/p/OrIjvqIsi4-


6
Hoàn hảo! Tôi đã bỏ lỡ cách bạn có thể sử dụng RawMessage. Chính xác những gì tôi cần. Về phần say, tôi thực sự vẫn muốn nó như vậy json.RawMessage, bởi vì chuỗi vẫn chưa được giải mã ( ký tự gói "và thoát \n, v.v.), vì vậy tôi cũng sẽ bỏ quản lý nó.
ANisus

1
Tôi đã sửa câu trả lời của mình để phù hợp với những gì bạn đã làm. Cảm ơn
Stephen Weinberg

3
Thay vào đó, kiểu phải là map [string] * json.RawMessage vì các phương thức Unmarshal / Marshal không được triển khai trên json.RawMessage.
albert

1
@albert, phù hợp với tôi: play.golang.org/p/XYsozrJrSl . Tuy nhiên, bạn đúng rằng sử dụng một con trỏ sẽ tốt hơn. Phần nghịch đảo của mã của tôi không hoạt động chính xác: play.golang.org/p/46JOdjPpVI . Sử dụng con trỏ sẽ khắc phục sự cố này: play.golang.org/p/ZGwhXkYUT3 .
Stephen Weinberg,

3
Sau khi bạn cập nhật lên * json.RawMessage, bây giờ bạn cần phải tham khảo chúng trong các lệnh gọi tới json.Unmarshal.
Kyle Lemons

2

Ngoài câu trả lời của Stephen Weinberg, kể từ đó, tôi đã triển khai một công cụ tiện dụng có tên là iojson , giúp đưa dữ liệu vào một đối tượng hiện có một cách dễ dàng cũng như mã hóa đối tượng hiện có thành một chuỗi JSON. Phần mềm trung gian iojson cũng được cung cấp để hoạt động với các phần mềm trung gian khác. Bạn có thể tìm thêm các ví dụ khác tại https://github.com/junhsieh/iojson

Thí dụ:

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

Đầu ra mẫu:

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

1

Đây là một cách thanh lịch để làm điều tương tự. Nhưng tại sao một phần JSON không gây chết người? Điều đó không có ý nghĩa.

  1. Tạo cấu trúc của bạn cho Trò chuyện.
  2. Giải mã json thành Struct.
  3. Bây giờ bạn có thể truy cập mọi thứ trong Struct / Object một cách dễ dàng.

Nhìn vào mã làm việc bên dưới. Sao chép và dán nó.

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

Đi chơi


1
Việc giải phóng một phần là cần thiết khi bạn đang làm việc với các cấu trúc gồm hàng trăm trường lồng nhau dưới dạng các đối tượng tạm thời. Ví dụ: lấy json từ máy chủ, cập nhật các trường đơn lẻ và đăng lại trên máy chủ.
Artem Baskakov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.