GoでJSONをマップに部分的に非整列化


98

私のWebSocketサーバーはJSONデータを受信して​​非整列化します。このデータは、常にキーと値のペアを持つオブジェクトにラップされます。キー文字列は値の識別子として機能し、Goサーバーにそれがどのような値であるかを伝えます。値のタイプを知ることで、値を正しいタイプの構造体に非整列化するJSONに進むことができます。

各jsonオブジェクトには、複数のキーと値のペアが含まれる場合があります。

JSONの例:

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

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

あらゆる提案/助けをありがとう!

回答:


194

これは、にアンマーシャリングすることで実現できます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-


6
パーフェクト!どのように使用できるか見逃しましたRawMessage。まさに私が必要としたもの。についてsayjson.RawMessage、文字列がまだデコードされていない(ラッピング"やエスケープされた文字\nなど)ため、実際にはとしても必要です。そのため、マーシャリングを解除します。
ANisus

1
私はあなたがしたことと一致するように私の答えを修正しました。ありがとう
スティーブンウェインバーグ

3
Unmarshal / Marshalメソッドはjson.RawMessageに実装されていないため、タイプは代わりにmap [string] * json.RawMessageである必要があります。
アルバート

1
@albert、私のために働きます:play.golang.org/p/XYsozrJrSl。ただし、ポインタを使用する方が適切であることは間違いありません。私のコードの逆が正しく機能しません:play.golang.org/p/46JOdjPpVI。ポインターを使用すると修正されます:play.golang.org/p/ZGwhXkYUT3
Stephen Weinberg

3
* json.RawMessageに更新した後、json.Unmarshalの呼び出しでそれらを逆参照する必要があります。
カイルレモン

2

Stephen Weinbergの回答に加えて、私はiojsonという便利なツールを実装しました。これは、既存のオブジェクトにデータを簡単に入力したり、既存のオブジェクトをJSON文字列にエンコードしたりするのに役立ちます。他のミドルウェアと連携するiojsonミドルウェアも提供されています。その他の例はhttps://github.com/junhsieh/iojsonにあります

例:

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

出力例:

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

同様のことを行うエレガントな方法を次に示します。しかし、なぜ部分的にJSONが非整列化されるのですか?それは意味がありません。

  1. チャット用の構造体を作成します。
  2. jsonをStructにデコードします。
  3. これで、Struct / Objectのすべてに簡単にアクセスできます。

以下の作業コードを見てください。コピーして貼り付けます。

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

遊び場に行く


数百のネストされたフィールドの構造を一時オブジェクトとして使用する場合は、部分的な非整列化が必要です。たとえば、サーバーからjsonを取得し、単一のフィールドを更新してサーバーにポストバックします。
アルテムバスカコフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.