Teilweise JSON-Unmarschall in einer Karte in Go

96

Mein Websocket-Server empfängt und marshallt JSON-Daten. Diese Daten werden immer in ein Objekt mit Schlüssel / Wert-Paaren eingeschlossen. Die Schlüsselzeichenfolge fungiert als Wertkennung und teilt dem Go-Server mit, um welche Art von Wert es sich handelt. Wenn ich weiß, welcher Werttyp vorhanden ist, kann ich mit JSON fortfahren, um den Wert in den richtigen Strukturtyp zu entpacken.

Jedes json-Objekt kann mehrere Schlüssel / Wert-Paare enthalten.

Beispiel JSON:

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

Gibt es eine einfache Möglichkeit, das "encoding/json"Paket zu verwenden, um dies zu tun?

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

Vielen Dank für jede Art von Vorschlag / Hilfe!

ANisus
quelle

Antworten:

192

Dies kann durch Unmarshaling in a erreicht werden map[string]json.RawMessage.

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

Zum weiteren Analysieren sendMsgkönnen Sie dann Folgendes tun:

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

Für saySie können die gleiche Sache und Abstellungs in einen String tun:

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

BEARBEITEN: Beachten Sie, dass Sie auch die Variablen in Ihrer sendMsg-Struktur exportieren müssen, um die Zuordnung korrekt aufzuheben. Ihre Strukturdefinition wäre also:

type sendMsg struct {
    User string
    Msg  string
}

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

Stephen Weinberg
quelle
6
Perfekt! Ich habe vermisst, wie Sie verwenden könnten RawMessage. Genau das, was ich brauchte. Über say, ich möchte es eigentlich immer noch als json.RawMessage, weil die Zeichenfolge immer noch nicht dekodiert ist (Wrapping "und \nEscape-Zeichen usw.), also werde ich es auch ausmarschieren.
ANisus
1
Ich habe meine Antwort so korrigiert, dass sie mit Ihrer übereinstimmt. Vielen Dank
Stephen Weinberg
3
Der Typ sollte stattdessen map [string] * json.RawMessage sein, da Unmarshal / Marshal-Methoden in json.RawMessage nicht implementiert sind.
Albert
1
@albert, arbeitet für mich: play.golang.org/p/XYsozrJrSl . Sie haben jedoch Recht, dass die Verwendung eines Zeigers besser wäre. Die Umkehrung meines Codes funktioniert nicht richtig: play.golang.org/p/46JOdjPpVI . Die Verwendung eines Zeigers behebt das Problem : play.golang.org/p/ZGwhXkYUT3 .
Stephen Weinberg
3
Nachdem Sie auf * json.RawMessage aktualisiert haben, müssen Sie sie jetzt in den Aufrufen von json.Unmarshal dereferenzieren.
Kyle Lemons
2

Nach Stephen Weinbergs Antwort habe ich seitdem ein praktisches Tool namens iojson implementiert , mit dem Daten einfach in ein vorhandenes Objekt eingefügt und das vorhandene Objekt in eine JSON-Zeichenfolge codiert werden kann. Eine iojson-Middleware wird auch für die Arbeit mit anderen Middlewares bereitgestellt. Weitere Beispiele finden Sie unter https://github.com/junhsieh/iojson

Beispiel:

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

Beispielausgabe:

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
Jun Xie
quelle
1

Hier ist eine elegante Möglichkeit, ähnliche Dinge zu tun. Aber warum entlarvt JSON teilweise? Das macht keinen Sinn.

  1. Erstellen Sie Ihre Strukturen für den Chat.
  2. Dekodiere json in die Struktur.
  3. Jetzt können Sie einfach auf alles in Struct / Object zugreifen.

Schauen Sie sich unten den Arbeitscode an. Kopieren Sie es und fügen Sie es ein.

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

Geh auf den Spielplatz

Taban-Kosmos
quelle
Ein teilweises Unmarshalling ist erforderlich, wenn Sie mit Strukturen aus mehreren hundert verschachtelten Feldern als temporäre Objekte arbeiten. Holen Sie sich beispielsweise json vom Server, aktualisieren Sie einzelne Felder und veröffentlichen Sie es wieder auf dem Server.
Artem Baskakov