2017-11-01 19 views
1

オブジェクトの配列を含むJSONを返すAPIをリクエストしています。問題は、オブジェクトが2つの形式を取ることができることです。文字列でもオブジェクトでも構いません。例の結果は次のようになります。複数のJSON型を同じ構造体に解析する

[ 
    {"name": "obj1", "key2": ["a", "b"]}, 
    "obj2", 
    {"name": "obj3"} 
] 

文字列要素"objX"{"name": "objX"}と同等です。

私は、次のタイプのスライスにこれを解析する:

type Obj struct { 
    Name string 
    Key2 []string 
} 

私は合理的な方法でこれを行うにはどうすればよいですか?

答えて

2
package main 

import (
    "encoding/json" 
    "fmt" 
) 

type Obj struct { 
    Name string `json:"name"` 
    Key2 []string `json:"key2"` 
} 

func (o *Obj) UnmarshalJSON(b []byte) error { 
    var name string 
    if err := json.Unmarshal(b, &name); err == nil { 
     *o = Obj{} 
     o.Name = name 
     return nil 
    } 

    type Obj2 Obj 
    var o2 Obj2 
    if err := json.Unmarshal(b, &o2); err != nil { 
     return err 
    } 
    *o = Obj(o2) 
    return nil 
} 

const payload = `[ 
    {"name": "obj1", "key2": ["a", "b"]}, 
    "obj2", 
    {"name": "obj3"} 
] 
` 

func main() { 
    var objs []*Obj 
    if err := json.Unmarshal([]byte(payload), &objs); err != nil { 
     panic(err) 
    } 
    for _, obj := range objs { 
     fmt.Printf("Name:%v, Key2:%v\n", obj.Name, obj.Key2) 
    } 
} 

https://play.golang.org/p/rmtSOpkYqp

+0

セイ'Obj'構造体には多くのプロパティがあります。これを何度も繰り返さないようにする方法はありますか? –

+1

@MathiasBakはい、 'type Obj2 Obj'のような型宣言を使用し、型変換を使用して' * o'に結果を代入します: '* o = Obj(obj)'。 [Go Playground](https://play.golang.org/p/SCpSwg_vU-)の例を参照してください。私は個人的に構造体を複製する代わりにこれをお勧めします。あるいは、新しい型の 'Obj2 Obj型を宣言し、' o'自体を '* Obj2'型の値に代入してください:var obj * Obj2 =(* Obj2)(o)'結果をコピーしても、 'json'パッケージは' o'自体にアンマーシャルされます。 [Playground](https://play.golang.org/)でこれをご覧ください。これによりパフォーマンスが向上します。 – icza

0

あなたが期待するタイプの値にarrray別の解決策は、あなたのJSONの様々な要素を非整列化することであり、このプロセスは/あなたがそれを必要とすべきであるstringの値についてObjラッパーを作成します。

入力はJSON配列なので、配列またはスライスに非整列化することができます。また、エレメントのタイプが異なるため、Go配列またはスライスのエレメントタイプはinterface{}でなければなりません。

タイプ[]interface{}の値に非マーシャルすると、encoding/jsonパッケージがオブジェクト要素としてmap[string]interface{}を選択します。しかし、あなたは、あなたに非整列化したいタイプの要素を持つ前に、ターゲットスライスを取り込む場合jsonパッケージには素直にそれらを使用します。

func main() { 
    res := []interface{}{ 
     &Obj{}, 
     "", 
     &Obj{}, 
    } 
    if err := json.Unmarshal([]byte(src), &res); err != nil { 
     panic(err) 
    } 

    for _, v := range res { 
     fmt.Printf("type = %-10T value = %+q\n", v, v) 
    } 
} 

const src = `[ 
    {"name": "obj1", "key2": ["a", "b"]}, 
    "obj2", 
    {"name": "obj3"} 
]` 

出力(Go Playground上でそれを試してみてください):

type = *main.Obj value = &{"obj1" ["a" "b"]} 
type = string  value = "obj2" 
type = *main.Obj value = &{"obj3" []} 
関連する問題