2017-07-03 11 views
0

私はこのアイソーン:解析し、動的構造

{ 
    "tag1": 1, 
    "tag2": 7, 
    ... 
} 

のようなJSON構造を持っていると私は、タグ名はもちろん、完全に動的であり、この

data TagResult { name :: String, numberOfDevicesTagged :: Int } deriving (Show, Eq) 
newtype TagResultList = TagResultList { tags :: [TagResult] } 

のようなタイプがあると私は知りませんそれらはコンパイル時に JSONデータを解析するためにインスタンスを作成したいのですが、コンパイルできません。

これを行うにはどうすればparseJSONを定義できますか?

+0

'Map'には既存の' FromJSON'と 'ToJSON'タイプを使うことができます。あなたのタグがキーになります。 –

+1

[FromJSONの複数のフィールドからリストを作成する]の可能な複製(https://stackoverflow.com/questions/44514645/fromjson-make-a-list-from-multiple-fields) –

+0

[FromJSON make複数のフィールドからのリスト](https://stackoverflow.com/questions/44514645/fromjson-make-a-list-from-multiple-fields)前述のリンクは、コンパイル時にタグのリストがわかっている場合です。この場合、タグは不明です。 – Batou99

答えて

1

ObjectがHasMapであり、実行時にキーを抽出できるという事実を利用できます。

{-# LANGUAGE OverloadedStrings #-} 
module Main where 

import Data.Aeson 
import qualified Data.Text as T 
import qualified Data.HashMap.Lazy as HashMap 

data TagResult = TagResult { name :: String 
          , numberOfDevicesTagged :: Int 
          } deriving (Show, Eq) 


newtype TagResultList = TagResultList { tags :: [TagResult] } deriving Show 


instance ToJSON TagResult where 

    toJSON (TagResult tag ntag) = 
    object [ T.pack tag .= ntag ] 

instance ToJSON TagResultList where 

    toJSON (TagResultList tags) = 
    object [ "tagresults" .= toJSON tags ] 


instance FromJSON TagResult where 

    parseJSON (Object v) = 
    let (k, _) = head (HashMap.toList v) 
    in TagResult (T.unpack k) <$> v .: k 

    parseJSON _ = fail "Invalid JSON type" 

instance FromJSON TagResultList where 

    parseJSON (Object v) = 
    TagResultList <$> v .: "tagresults" 


main :: IO() 
main = do 

    let tag1 = TagResult "tag1" 1 
     tag2 = TagResult "tag2" 7 
     taglist = TagResultList [tag1, tag2] 

    let encoded = encode taglist 
     decoded = decode encoded :: Maybe TagResultList 

    print decoded 

上記のプログラムは、タグ結果リストを印刷する必要があります - 次のようにして、その後、FromJSONインスタンスを書くことができます。

Just (TagResultList {tags = [TagResult {name = "tag1", numberOfDevicesTagged = 1},TagResult {name = "tag2", numberOfDevicesTagged = 7}]})