2011-07-03 5 views
6

良い例が見つかりません。助けをお待ちしています。 JSONは以下の通りである。Haskell Aeson:Valueをカスタムタイプに変換する方法は?

[{ 
    "EXIF:Make": "Canon", 
    "EXIF:Model": "Canon PowerShot S95", 
    "EXIF:Orientation": "Horizontal (normal)", 
    "EXIF:XResolution": 180, 
    "EXIF:YResolution": 180, 
    "EXIF:ResolutionUnit": "inches" 
}] 

次のように私が使用したコードは次のとおりです。

data Exif = Exif [[(String, String)]] 

import Data.Aeson 
import Data.Attoparsec 
import Data.ByteString 
x <- fmap (parse json) (Data.ByteString.readFile "json.txt") 

にはどうすれば&はへxから変換することFromJSONタイプを使用して定義しますまたは同様のデータ構造ですか? [[]]に注意してください - JSONに複数のトップレベルエントリがあることを期待しています。

答えて

15

はここで慣用的なソリューションです:

{-# LANGUAGE OverloadedStrings #-} 

module Main 
     where 

import Control.Applicative 
import Control.Monad 
import Data.Aeson 
import Data.Attoparsec 

import qualified Data.ByteString as B 
import qualified Data.Text as T 

data ExifEntry = ExifEntry { exifMake :: T.Text, 
          exifModel :: T.Text, 
          exifOrientation :: T.Text, 
          exifXResolution :: Int, 
          exifYResolution :: Int, 
          exifResolutionUnit :: T.Text 
          } deriving (Eq, Show) 


instance FromJSON ExifEntry 
    where 
    parseJSON (Object v) = ExifEntry <$> 
          v .: "EXIF:Make" <*> 
          v .: "EXIF:Model" <*> 
          v .: "EXIF:Orientation" <*> 
          v .: "EXIF:XResolution" <*> 
          v .: "EXIF:YResolution" <*> 
          v .: "EXIF:ResolutionUnit" 
    parseJSON _   = mzero 


parseAll :: B.ByteString -> [ExifEntry] 
parseAll s = case (parse (fromJSON <$> json) s) of 
    Done _ (Error err) -> error err 
    Done ss (Success e) -> e:(parseAll ss) 
    _     -> [] 

main :: IO() 
main = do s <- B.readFile "json.txt" 
      let p = parseAll s 
      print p 

テスト:代わり

$ cat json.txt 
{ 
    "EXIF:Make": "Canon", 
    "EXIF:Model": "Canon PowerShot S95", 
    "EXIF:Orientation": "Horizontal (normal)", 
    "EXIF:XResolution": 180, 
    "EXIF:YResolution": 180, 
    "EXIF:ResolutionUnit": "inches" 
} 

{ 
    "EXIF:Make": "Canon", 
    "EXIF:Model": "Canon PowerShot S995", 
    "EXIF:Orientation": "Horizontal (normal)", 
    "EXIF:XResolution": 180, 
    "EXIF:YResolution": 180, 
    "EXIF:ResolutionUnit": "inches" 
} 
$ ./dist/build/test/test 
[ExifEntry {exifMake = "Canon", exifModel = "Canon PowerShot S95", exifOrientation = "Horizontal (normal)", exifXResolution = 180, exifYResolution = 180, exifResolutionUnit = "inches"},ExifEntry {exifMake = "Canon", exifModel = "Canon PowerShot S995", exifOrientation = "Horizontal (normal)", exifXResolution = 180, exifYResolution = 180, exifResolutionUnit = "inches"}] 

は、ここにあなたが要求されたデータ型([[(Text,Text)]])を与えることslightly more ugly solutionです。

+1

+1私が見つけた最初の完全なaesonの例の1つ!ありがとう! – oliver