2011-08-03 84 views
13

previous post開始,我發現我完全卡住了。我試圖將JSON結構解析爲我自己的類型,不僅我堅持如何解析數組,我甚至不確定是否按照預期使用了Aeson庫。任何幫助將不勝感激。解析爲自定義類型的Haskell,Aeson&JSON

代碼:

data Exif = Exif [(T.Text, ExifValue)] deriving (Show) 
data ExifValue = 
    ExifText T.Text | 
    ExifInt Integer | 
    ExifDouble Double | 
    ExifBool Bool | 
    ExifArray [ExifValue] 
    deriving (Show) 

instance FromJSON ExifValue where 
    parseJSON (Number (I n)) = return $ ExifInt n 
    parseJSON (Number (D n)) = return $ ExifDouble n 
    parseJSON (String s)  = return $ ExifText s 
    parseJSON (Bool b)  = return $ ExifBool b 
    -- parseJSON (Array a)  = ????? 

instance FromJSON Exif where 
    parseJSON (Object o) = do 
     x <- sequence $ map f (M.assocs o) 
     return $ Exif x 
     where 
     f (t, x) = do 
      y <- parseJSON x 
      return ((t, y) :: (T.Text, ExifValue)) 

parseExifFile = fmap parseExifData . B.readFile 

parseExifData :: B.ByteString -> Data.Attoparsec.Result (Data.Aeson.Result [Exif]) 
parseExifData content = parse (fmap fromJSON json) content 

測試文件:

[{ 
    "SourceFile": "test.jpg", 
    "ExifTool:ExifToolVersion": 8.61, 
    "File:FileName": "test.jpg", 
    "File:FileSize": 2174179, 
    "File:FileModifyDate": "2011:07:27 16:53:49-07:00", 
    "File:FilePermissions": 644, 
    "File:FileType": "JPEG", 
    "File:MIMEType": "image/jpeg", 
    "File:ExifByteOrder": "MM", 
    "File:CurrentIPTCDigest": "32d6a77098a73aa816f2570c9472735a", 
    "File:ImageWidth": 2592, 
    "File:ImageHeight": 1936, 
    "File:EncodingProcess": 0, 
    "File:BitsPerSample": 8, 
    "File:ColorComponents": 3, 
    "File:YCbCrSubSampling": "2 2", 
    "XMP:Subject": ["alpha","beta","gamma"] 
}] 

回答

10

你必須遵循的parseJSON類型一點點下來一隻兔子的蹤跡,但一旦你認識到什麼(Array a)代表,它應該是直截了當的。

parseJSON有類型Value -> Parser a,所以(Array a)有類型ValueValue類型中的變體之一是Array Array,因此a(Array a)必須是Array的類型,其定義爲Vector Value。 裏面Vector是什麼你想打電話給parseJSON返回你的清單,所以看看你可以用Vector做什麼。

最簡單的方法可能會將a轉換爲Vector.toList的列表,然後使用mapM解析Values

或者,您可以通過更改ExifArray變體以保留Vector ExifValue,然後使用Vector.mapM來避免Vector列出轉換。

5

我不是母語爲英語的人,所以我可能不會很瞭解你。我想你想知道如何解析json到你呈現的ExifValue這樣的遞歸數據類型。 所以我做了一個簡單的例子來演示如何將json解析爲遞歸數據類型。

{-# LANGUAGE OverloadedStrings #-} 
import qualified Data.ByteString as B 
import Data.Maybe 
import Control.Monad 
import Control.Applicative 
import Data.Attoparsec 
import Data.Attoparsec.Number 
import Data.Aeson 
import qualified Data.Vector as V 

data Data = D1 Int | D2 [Data] 
    deriving (Show) 

instance FromJSON Data where 
    parseJSON (Number (I n)) = return $ D1 $ fromInteger n 
    parseJSON (Array a) = D2 <$> mapM parseJSON (V.toList a) 

main = do 
    let v = fromJust $ maybeResult $ parse json "[1,2,3,[5,3,[6,3,5]]]" 
    let v1 :: Data 
     v1 = case fromJSON v of 
       Success a -> a 
       Error s -> error s 
    print v1 
3

aeson library (0.3.2.12)的一個稍微更新的版本支持自動生成JSON實例。

{-# LANGUAGE TemplateHaskell #-} 

import Data.Aeson 
import Data.Aeson.TH (deriveJSON) 
import Data.Attoparsec 
import qualified Data.ByteString as B 
import qualified Data.Text as T 

data Exif = Exif [(T.Text, ExifValue)] deriving (Show) 
data ExifValue = 
    ExifText T.Text | 
    ExifInt Integer | 
    ExifDouble Double | 
    ExifBool Bool | 
    ExifArray [ExifValue] 
    deriving (Show) 

deriveJSON id ''Exif 
deriveJSON id ''ExifValue 

parseExifFile = fmap parseExifData . B.readFile 

parseExifData :: B.ByteString -> Data.Attoparsec.Result (Data.Aeson.Result [Exif]) 
parseExifData content = parse (fmap fromJSON json) content 

產地:

instance ToJSON Exif where 
    { toJSON 
     = \ value_a1Va 
      -> case value_a1Va of { Exif arg1_a1Vb -> toJSON arg1_a1Vb } } 
instance FromJSON Exif where 
    { parseJSON 
     = \ value_a1Vc 
      -> case value_a1Vc of { 
       arg_a1Vd -> (Exif Data.Functor.<$> parseJSON arg_a1Vd) } } 

instance ToJSON ExifValue where 
    { toJSON 
     = \ value_a1Wd 
      -> case value_a1Wd of { 
       ExifText arg1_a1We 
       -> object [(T.pack "ExifText" .= toJSON arg1_a1We)] 
       ExifInt arg1_a1Wf 
       -> object [(T.pack "ExifInt" .= toJSON arg1_a1Wf)] 
       ExifDouble arg1_a1Wg 
       -> object [(T.pack "ExifDouble" .= toJSON arg1_a1Wg)] 
       ExifBool arg1_a1Wh 
       -> object [(T.pack "ExifBool" .= toJSON arg1_a1Wh)] 
       ExifArray arg1_a1Wi 
       -> object [(T.pack "ExifArray" .= toJSON arg1_a1Wi)] } } 
instance FromJSON ExifValue where 
    { parseJSON 
     = \ value_a1Wj 
      -> case value_a1Wj of { 
       Object obj_a1Wk 
       -> case Data.Map.toList obj_a1Wk of { 
         [(conKey_a1Wl, conVal_a1Wm)] 
         -> case conKey_a1Wl of { 
          _ | (conKey_a1Wl == T.pack "ExifText") 
           -> case conVal_a1Wm of { 
            arg_a1Wn 
             -> (ExifText Data.Functor.<$> parseJSON arg_a1Wn) } 
           | (conKey_a1Wl == T.pack "ExifInt") 
           -> case conVal_a1Wm of { 
            arg_a1Wo 
             -> (ExifInt Data.Functor.<$> parseJSON arg_a1Wo) } 
           | (conKey_a1Wl == T.pack "ExifDouble") 
           -> case conVal_a1Wm of { 
            arg_a1Wp 
             -> (ExifDouble Data.Functor.<$> parseJSON arg_a1Wp) } 
           | (conKey_a1Wl == T.pack "ExifBool") 
           -> case conVal_a1Wm of { 
            arg_a1Wq 
             -> (ExifBool Data.Functor.<$> parseJSON arg_a1Wq) } 
           | (conKey_a1Wl == T.pack "ExifArray") 
           -> case conVal_a1Wm of { 
            arg_a1Wr 
             -> (ExifArray Data.Functor.<$> parseJSON arg_a1Wr) } 
           | otherwise -> Control.Monad.mzero } 
         _ -> Control.Monad.mzero } 
       _ -> Control.Monad.mzero } }