json haskell aeson

Haskell, Aeson y JSON analizando en tipo personalizado



(3)

Después de una publicación anterior , descubrí que estoy totalmente estancado. Estoy tratando de analizar una estructura JSON en mi propio tipo, y no solo estoy atascado en cómo analizar la matriz, ni siquiera estoy seguro de si estoy usando la biblioteca Aeson como estaba previsto. Cualquier ayuda sería muy apreciada.

El código:

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

El archivo de prueba:

[{ "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"] }]


Tienes que seguir el tipo de parseJSON un poco por un sendero de conejo, pero una vez que reconoces lo que (Array a) representa, debería ser sencillo.

parseJSON tiene el tipo Value -> Parser a , entonces (Array a) tiene el tipo Value . Una de las variantes en el tipo de Value es Array Array , por lo que a en (Array a) debe ser del tipo Array , que se define como Vector Value . Los Value ''s dentro de ese Vector son a lo que usted quiere llamar parseJSON para devolver su lista, así que consulte lo que puede hacer con un Vector .

El enfoque más fácil sería convertir a a una lista con Vector.toList , y luego usar mapM para analizar los Values .

Alternativamente, puede evitar el Vector para ExifArray conversión cambiando su variante ExifArray para que contenga Vector ExifValue , y luego use Vector.mapM .


No soy un hablante nativo de inglés, así que puede que no te entienda muy bien. Supongo que quieres saber cómo analizar json en un tipo de datos recursivos como ExifValue has presentado. Así que hice un ejemplo simple para mostrar cómo analizar JSON en el tipo de datos recursivo.

{-# 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


Una versión un poco más nueva de la biblioteca aeson (0.3.2.12) admite autogenerar instancias 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

Produce:

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 } }