2016-07-05 7 views
2

RESTサーバーから複雑な形式のJSON応答を使用しています。それらをデコードするには、さまざまなネストされたオブジェクトを処理するための2つのデータ型があります。例:Aesonは文字列またはintのいずれかのJSONオブジェクトをデコードします

... Other types ... 

data Profile = 
    Profile { fields :: [KVPair] 
    } deriving (Show) 

instance FromJSON Profile where 
    parseJSON (Object v) = 
    Profile <$> v .: "Fields" 
    parseJSON _ = mzero 

data KVPair = 
    KVPair { key :: Int 
     , value :: String 
    } deriving (Show) 

instance FromJSON KVPair where 
    parseJSON (Object v) = 
    KVPair <$> v .: "Key" 
      <*> v .: "Value" 
    parseJSON _ = mzero 

最終的なKVPairタイプ以外はすべて動作します。 JSONオブジェクトにはすべて整数キーがあります。ただし、値は、整数または文字列になります

 { 
     "Key": 0, 
     "Value": "String Value!" 
     }, 
     { 
     "Key": 1, 
     "Value": 42 
     } 

は今、私はStringIntで構成され、私の価値デコードに別の合計の種類を追加することができると仮定したが、私は全体を追加しないことを好むだろうそのための新しいタイプ。 Aesonはこのシナリオを処理する簡単な方法はありますか?

答えて

4

2つの簡単な修正があります。一つは、単に

data KVPair = KVPair { key :: Int, value :: Value } 

を書いて、同じ他のすべてのコードを残すことです。消費者はValueをチェックして文字列かどうかを調べる必要があります。

恐らく、より良い方法は、両方とも希望する形式に変換する2つの代替パーサーを用意することです。例えば、そのままごKVPair定義を保ち、1は、両方の長所は、それがStringや周りIntは、値の他の種類を拒否するのかどうかについての情報を維持するだろう

showInt :: Int -> String 
showInt = show 

instance FromJSON KVPair where 
    parseJSON (Object v) 
     = KVPair 
     <$> v .: "Key" 
     <*> (v .: "Value" <|> (showInt <$> v .: "Value")) 

書くかもしれません。例えば

data KVPair = KVPair { key :: Int, value :: Either String Int } 

instance FromJSON KVPair where 
    parseJSON (Object v) 
     = KVPair 
     <$> v .: "Key" 
     <*> ( (Left <$> v .: "Value") 
      <|> (Right <$> v .: "Value") 
      ) 
+0

代替構文解析メソッドが正しく理解されていれば、整数値を文字列型に変換するだけでしょうか? "Value":3はKVPair {value = "3"}のようなものに変換されますか? – jkeuhlen

+2

@jkeuhlen正確には、 "強制"はここには適用されないハスケルの特定の意味を持っています - "変換"または "かわいいプリント"は正解に近いでしょう。 –

1

すべてのJSON値が可能なフィールドを持つオブジェクトを操作するには、Aeson Value型を使用するだけです。

+0

オブジェクトは既に(Aesonの)HashMapです。必要な値だけを参照してください。これで十分ではない場合、JSONをいずれかの文字列に変換することができます – dysinger

関連する問題