155 votes

Unmarshal partiellement JSON dans une carte en Go

Mon serveur websocket recevra et décompressera des données JSON. Ces données seront toujours enveloppées dans un objet avec des paires clé/valeur. La chaîne de clés servira d'identifiant de la valeur, indiquant au serveur Go de quel type de valeur il s'agit. En sachant de quel type de valeur il s'agit, je peux alors procéder à l'unmarshal JSON de la valeur dans le bon type de structure.

Chaque objet json peut contenir plusieurs paires clé/valeur.

Exemple JSON :

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

Existe-t-il un moyen simple d'utiliser la fonction "encoding/json" pour ce faire ?

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

Merci pour toute suggestion ou aide !

276voto

Stephen Weinberg Points 12682

Pour ce faire, il convient d'appliquer la méthode Unmarshaling dans un fichier map[string]json.RawMessage .

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

Pour poursuivre l'analyse sendMsg vous pourriez alors faire quelque chose comme :

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

Pour say il est possible de faire la même chose et d'annuler la démarcation dans une chaîne de caractères :

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

EDITAR: Gardez à l'esprit que vous devrez également exporter les variables dans votre structure sendMsg pour que l'annulation soit correcte. La définition de votre structure serait donc la suivante

type sendMsg struct {
    User string
    Msg  string
}

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

5voto

Taban Cosmos Points 338

Voici une manière élégante de faire la même chose. Mais pourquoi faire en partie du JSON unmarshal ? Cela n'a pas de sens.

  1. Créez vos structures pour le Chat.
  2. Décoder le json vers la structure.
  3. Vous pouvez désormais accéder facilement à tout ce qui se trouve dans Struct/Object.

Vous trouverez ci-dessous le code de travail. Copiez-le et collez-le.

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

Aller à l'aire de jeux

3voto

Jun Xie Points 986

Suite à la réponse de Stephen Weinberg, j'ai depuis mis en place un outil pratique appelé iojson qui permet d'ajouter facilement des données à un objet existant et d'encoder l'objet existant dans une chaîne JSON. Un intergiciel iojson est également fourni pour travailler avec d'autres intergiciels. D'autres exemples sont disponibles à l'adresse suivante https://github.com/junhsieh/iojson

Exemple :

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

Exemple de sortie :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X