Częściowo JSON unmarshal na mapie w Go

Mój serwer websocket będzie odbierał i odbierał dane JSON. Dane te będą zawsze zawinięte w obiekt z parami klucz / wartość. Klucz-łańcuch będzie działał jako identyfikator wartości, informując serwer Go, jakiego rodzaju jest to wartość. Wiedząc jaki typ wartości, mogę następnie przejść do JSON unmarshal wartość do właściwego typu struktury.

Każdy obiekt json może zawierać wiele par klucz / wartość.

Przykład JSON:

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

Czy Jest jakiś łatwy sposób użycia "encoding/json" pakietu do zrobić to?

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

Dzięki za każdą sugestię / pomoc!

 70
Author: ANisus, 2012-06-17

2 answers

Można to osiągnąć poprzez Unmarshalling w map[string]*json.RawMessage.

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

Aby dalej analizować sendMsg, możesz zrobić coś w stylu:

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

Dla say, możesz zrobić to samo i unmarshal w ciągu:

var str string
err = json.Unmarshal(*objmap["say"], &str)
 147
Author: Stephen Weinberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-28 18:37:51

Kontynuując odpowiedź Stephena Weinberga, zaimplementowałem przydatne narzędzie o nazwie iojson , które pomaga w łatwym wypełnianiu danych do istniejącego obiektu, a także kodowaniu istniejącego obiektu do ciągu JSON. Oprogramowanie pośredniczące iojson jest również dostarczane do pracy z innymi urządzeniami pośredniczącymi. Więcej przykładów można znaleźć na stronie https://github.com/junhsieh/iojson

Przykład:

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

Przykładowe wyjście:

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
 0
Author: Jun Xie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-03 18:36:09