How to parse an array with Haskell Aeson
aeson, haskell, json
Solution
Aeson has an instance for list, so I think it is not necessary to deal with vectors.
{-# LANGUAGE LambdaCase #-}
import Data.Aeson
data Series = Series [DataPoint]
data DataPoint = DataPoint Int Int
instance FromJSON DataPoint where
parseJSON jsn = do
[x,y] <- parseJSON jsn
return $ DataPoint x y
instance FromJSON Series where
parseJSON = \case
Object o -> (o .: "series") >>= fmap Series . parseJSON
x -> fail $ "unexpected json: " ++ show x
Problem
I have a JSON doc that looks like: ``` { "series": [[1,2], [2,3], [3,4]] } ``` I'd like to parse this into a set of data types: ``` data Series = Series [DataPoint] data DataPoint = DataPoint Int Int -- x and y ``` I'm having lots of problems trying to write the `FromJSON` instance for DataPoint. ``` instance FromJSON DataPoint where parseJSON (Array a) = ??? ``` I've tried using Lens to destruct the DataPoint record, but it doesn't compile: ``` case a ^.. values . _Integer of -} [x,y] -> DataPoint <$> x <*> y _ -> mzero ``` That fails with this error (the first two lines I get even absent the lens trickery, just trying to create a `DataPoint <$> 1 <*> 2`): ``` Couldn't match type ‘aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser Integer’ with ‘Integer’ Expected type: (aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser Integer -> Const (Data.Monoid.Endo [aeson-0.7.0.6:Data.Aeson.Types.Internal.Parse (aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser I -> Value -> Const (Data.Monoid.Endo [aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser Value Actual type: (Integer -> Const (Data.Monoid.Endo [aeson-0.7.0.6:Data.Aeson.Types.Internal.Parse Integer) -> Value -> Const (Data.Monoid.Endo [aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser Value In the second argument of ‘(.)’, namely ‘_Integer’ In the second argument of ‘(^..)’, namely ‘values . _Integer’ ``` Is there a better way to do this? Does anybody have an example of parsing arrays of values into a more detailed structure?