2012-06-16 14 views
62

Il mio server Websocket riceverà e dati JSON unmarshal. Questi dati saranno sempre racchiusi in un oggetto con coppie chiave/valore. La stringa di chiavi fungerà da identificatore di valore, dicendo al server Go che tipo di valore è. Sapendo quale tipo di valore, posso quindi passare a JSON unmarshal il valore nel tipo corretto di struct.In parte JSON unmarshal in una mappa in Go

Ogni oggetto json può contenere più coppie chiave/valore.

Esempio JSON:

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

C'è un modo semplice utilizzando il pacchetto "encoding/json" per fare questo?

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

Grazie per qualsiasi tipo di suggerimento/aiuto!

risposta

129

Questo può essere eseguito da Unmarshalling in map[string]*json.RawMessage.

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

Per analizzare ulteriormente sendMsg, si potrebbe poi fare qualcosa di simile:

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

Per say, si può fare la stessa cosa e unmarshalling in una stringa:

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

Perfetto! Ho perso il modo in cui potresti usare 'RawMessage'. Esattamente quello di cui avevo bisogno. Riguardo 'say', in realtà lo voglio ancora come' json.RawMessage', perché la stringa non è ancora decodificata (avvolgendo '' 'e caratteri di escape' \ n'-caratteri, ecc.), Quindi anche io sarò unmarshal. – ANisus

+1

I Ho risolto la mia risposta per corrispondere a quello che hai fatto. Grazie –

+3

Il tipo dovrebbe essere map [stringa] * json.RawMessage invece perché i metodi Unmarshal/Marshal non sono implementati su json.RawMessage. – albert

0

A seguito La risposta di Stephen Weinberg, da allora ho implementato un pratico strumento chiamato iojson, che aiuta a popolare facilmente i dati su un oggetto esistente così come codifica l'oggetto esistente in una stringa JSON. Un middleware iojson è anche fornito per funzionare con altri middleware. Altri esempi possono essere trovati a https://github.com/junhsieh/iojson

Esempio:

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

Esempio di output:

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 
Problemi correlati