2017-12-20 6 views
2

Ich habe verschiedene Strukturen, die ein Feld teilen, und ich muss eine JSON-Datei in die entsprechende Struktur in Go dekodieren.Golang elegant JSON dekodieren verschiedene Strukturen

Beispiel:

type Dog struct { 
    AnimalType string //will always be "dog" 
    BarkLoudnessLevel int 
} 

type Cat struct { 
    AnimalType string //will always be "cat" 
    SleepsAtNight bool 
} 

Wenn ich eine dieser Strukturen als JSON-String erhalte, was wäre die eleganteste Weg, um es in die richtige Struktur der Parsen?

+0

Ich würde mit dem Beispiel auf der Go-Website beginnen: https://golang.org/pkg/encoding/json/ (siehe unter "Beispiel (CustomMarshalJSON)") –

+0

Siehe das "Beispiel (Unmarshal) "für den Typ [' json.RawMessage] (https://golang.org/pkg/encoding/json/#RawMessage). – maerics

Antwort

5

Also gibt es ein paar Möglichkeiten, dies zu tun, aber die einfachste ist wahrscheinlich Deserialisierung der Payload zweimal und bedingte Verzweigungen basierend auf dem Attribut "AnimalType" in Ihrer Nutzlast. Hier ist ein einfaches Beispiel eines Zwischen Deserialisierung Modell:

package main 

import (
    "fmt" 
    "encoding/json" 
) 

type Dog struct { 
    AnimalType string //will always be "dog" 
    BarkLoudnessLevel int 
} 

type Cat struct { 
    AnimalType string //will always be "cat" 
    SleepsAtNight bool 
} 

var (
    payloadOne = `{"AnimalType":"dog","BarkLoudnessLevel":1}` 
    payloadTwo = `{"AnimalType":"cat","SleepsAtNight":false}` 
) 

func main() { 
    parseAnimal(payloadOne) 
    parseAnimal(payloadTwo) 
} 

func parseAnimal(payload string) { 
    animal := struct{ 
    AnimalType string 
    }{} 
    if err := json.Unmarshal([]byte(payload), &animal); err != nil { 
    panic(err) 
    } 
    switch animal.AnimalType { 
    case "dog": 
    dog := Dog{} 
    if err := json.Unmarshal([]byte(payload), &dog); err != nil { 
     panic(err) 
    } 
    fmt.Printf("Got a dog: %v\n", dog) 
    case "cat": 
    cat := Cat{} 
    if err := json.Unmarshal([]byte(payload), &cat); err != nil { 
     panic(err) 
    } 
    fmt.Printf("Got a cat: %v\n", cat) 
    default: 
    fmt.Println("Unknown animal") 
    } 
} 

Sehen sie in Aktion here.


IMO eine bessere Möglichkeit der Annäherung an diese die „Metadaten“ in eine Grundstruktur für die Nutzlast bewegt, obwohl dies erfordert die erwartete json Nutzlast zu modifizieren. So zum Beispiel, wenn Sie mit Nutzlasten arbeiten, die aussahen:

{"AnimalType":"dog", "Animal":{"BarkLoudnessLevel": 1}} 

Dann könnten Sie so etwas wie json.RawMessage verwenden, um teilweise die Struktur zu analysieren und dann bedingt den Rest analysieren wie notwendig (anstatt alles Parsen zweimal) - - führt auch zu einer besseren Trennung der Strukturattribute. Hier ist ein Beispiel dafür, wie Sie das tun würden:

package main 

import (
    "encoding/json" 
    "fmt" 
) 

type Animal struct { 
    AnimalType string 
    Animal  json.RawMessage 
} 

type Dog struct { 
    BarkLoudnessLevel int 
} 

type Cat struct { 
    SleepsAtNight bool 
} 

var (
    payloadOne = `{"AnimalType":"dog", "Animal":{"BarkLoudnessLevel": 1}}` 
    payloadTwo = `{"AnimalType":"cat", "Animal":{"SleepsAtNight": false}}` 
) 

func main() { 
    parseAnimal(payloadOne) 
    parseAnimal(payloadTwo) 
} 

func parseAnimal(payload string) { 
    animal := &Animal{} 
    if err := json.Unmarshal([]byte(payload), &animal); err != nil { 
     panic(err) 
    } 
    switch animal.AnimalType { 
    case "dog": 
     dog := Dog{} 
     if err := json.Unmarshal(animal.Animal, &dog); err != nil { 
      panic(err) 
     } 
     fmt.Printf("Got a dog: %v\n", dog) 
    case "cat": 
     cat := Cat{} 
     if err := json.Unmarshal(animal.Animal, &cat); err != nil { 
      panic(err) 
     } 
     fmt.Printf("Got a cat: %v\n", cat) 
    default: 
     fmt.Println("Unknown animal") 
    } 
} 

Und in Aktion here.