2012-06-16 7 views
62

Mi servidor websocket recibirá y eliminará los datos JSON. Estos datos siempre estarán envueltos en un objeto con pares clave/valor. La cadena clave actuará como identificador de valor, indicando al servidor Go qué clase de valor es. Al saber qué tipo de valor, puedo pasar a JSON para poner el valor en el tipo correcto de estructura.Parcialmente JSON unmarshal en un mapa en Go

Cada json-object puede contener varios pares de clave/valor.

Ejemplo JSON:

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

¿Hay alguna forma fácil utilizando el paquete "encoding/json" para hacer esto?

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

¡Gracias por cualquier tipo de sugerencia/ayuda!

Respuesta

129

Esto se puede lograr mediante Unmarshalling en un map[string]*json.RawMessage.

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

Para analizar más sendMsg, entonces podría hacer algo como:

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

Para say, se puede hacer lo mismo y unmarshal en una cadena:

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

Perfect! Me he perdido cómo puedes usar 'RawMessage'. Exactamente lo que necesitaba. Acerca de 'say', en realidad todavía lo quiero como' json.RawMessage', porque la cadena todavía no está decodificada (envolviendo '" 'y escapándolos' \ n'-characters, etc.), así que también lo desempaquelaré. – ANisus

+1

I corrigió mi respuesta para que coincida con lo que hizo. Gracias –

+3

El tipo debe ser map [cadena] * json.RawMessage en su lugar porque los métodos Unmarshal/Marshal no están implementados en json.RawMessage. – albert

0

Además de La respuesta de Stephen Weinberg, desde entonces he implementado una herramienta práctica llamada iojson, que ayuda a poblar datos a un objeto existente fácilmente y en codificando el objeto existente en una cadena JSON. También se proporciona un middleware iojson para trabajar con otros middlewares. Más ejemplos se pueden encontrar en https://github.com/junhsieh/iojson

Ejemplo:

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

Resultado de muestra:

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