2017-12-20 21 views
2

私はフィールドを共有する構造が異なり、JSONファイルをGoの対応する構造にデコードする必要があります。GolangはエレガントにJSONで異なる構造をデコードします

例:私はJSON文字列としてこれらの構造のうちの1つを受けていた場合

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

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

、何がその適切な構造にそれを解析する最もエレガントな方法だろうか?

+0

GoのWebサイト(https://golang.org/pkg/encoding/json/)で提供されている例を見てみましょう(「Example(CustomMarshalJSON)」を参照) –

+0

「例(非マーシャル) "[' json.RawMessage'タイプ](https://golang.org/pkg/encoding/json/#RawMessage)のためのものです。 – maerics

答えて

5

これを行うにはいくつかの方法がありますが、ペイロードの「AnimalType」属性に基づいて条件分岐を2回デシリアライズすることが最も簡単です。ここでは、中間デシリアライズモデルを使用した簡単な例です:

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

は、アクションhereでそれを参照してください。


IMO、これが予想されるJSONペイロードを変更する必要がありけれども、これは、親構造へのペイロードの「メタデータ」を移動している近づいてのより良い方法。あなたはのように見えたペイロードを使用していたのであれば、例えば、:

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

その後は、部分的な構造を解析し、必要に応じて、その後、条件付きで(むしろ二回すべてを解析するよりも)残りを解析するjson.RawMessageのようなものを使用することができます - また、構造属性のより良い分離をもたらす。あなたがそれを行う方法の例を次に示します:

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

そして、アクションhereです。

関連する問題