web-dev-qa-db-fra.com

En partie JSON unmarshal sur une carte dans Go

Mon serveur Websocket recevra et restaure les données JSON. Ces données seront toujours encapsulées dans un objet avec des paires clé/valeur. La chaîne de caractères jouera le rôle d'identificateur de valeur, indiquant au serveur Go quel type de valeur il s'agit. En sachant quel type de valeur, je peux alors passer à JSON pour dissocier la valeur du type correct 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 le "encoding/json" package pour faire cela?

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 tout type de suggestion/aide!

85
ANisus

Ceci peut être accompli en décomposant dans un map[string]*json.RawMessage.

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

Pour analyser plus en profondeur sendMsg, vous pouvez alors faire quelque chose comme:

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

Pour say, vous pouvez faire la même chose et le transformer en une chaîne:

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

EDIT: N'oubliez pas que vous devrez également exporter les variables de votre structure sendMsg dans un marshal correctement. Donc, votre définition de structure serait:

type sendMsg struct {
    User string
    Msg  string
}

Exemple: https://play.golang.org/p/RJbPSgBY6gZ

170
Stephen Weinberg

Suite à la réponse de Stephen Weinberg, j'ai depuis mis en place un outil pratique appelé iojson , qui permet de renseigner facilement des données dans un objet existant, ainsi que de coder l'objet existant en une chaîne JSON. Un middleware iojson est également fourni pour fonctionner avec d'autres middlewares. Plus d'exemples peuvent être trouvés à 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
1
Jun Xie