我有一个JSON文档,它看起来像:
{ "series": [[1,2], [2,3], [3,4]] }我想将其解析为一组数据类型:
data Series = Series [DataPoint]
data DataPoint = DataPoint Int Int -- x and y我在为FromJSON编写DataPoint实例时遇到了很多问题。
instance FromJSON DataPoint where
parseJSON (Array a) = ???我尝试过使用Lens来销毁DataPoint记录,但它没有编译:
case a ^.. values . _Integer of -}
[x,y] -> DataPoint <$> x <*> y
_ -> mzero这个错误失败了(前两行我甚至没有镜头欺骗,只是试图创建一个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’有更好的方法吗?
是否有将值数组解析为更详细的结构的示例?
发布于 2014-07-14 18:33:30
伊索有列表的例子,所以我认为没有必要处理向量。
{-# 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发布于 2014-07-14 18:27:39
这里的诀窍是使FromJSON DataPoint的实例正确,这需要一些匹配,但并不太糟糕。我想出了
instance FromJSON DataPoint where
parseJSON (Array v)
| V.length v == 2 = do
x <- parseJSON $ v V.! 0
y <- parseJSON $ v V.! 1
return $ DataPoint x y
| otherwise = mzero
parseJSON _ = mzero如果它不能为x和y提取出两个x,那么它将无法进行干净的解析。然后,只需定义Series的实例即可。
instance FromJSON Series where
parseJSON (Object o) = do
pts <- o .: "series"
ptsList <- mapM parseJSON $ V.toList pts
return $ Series ptsList
parseJSON _ = mzero再一次,如果数据在任何地方都有错误,它就会彻底失败。测试:
> decode "{\"series\": [[1, 2], [3, 4]]}" :: Maybe Series
Just (Series [DataPoint 1 2, DataPoint 3 4])
> decode "{\"series\": [[1, 2], [3, {}]]}" :: Maybe Series
Nothing所以看起来很管用。
编辑:正如@maxtaldykin所指出的那样,您可以利用实例
instance FromJSON DataPoint where
parseJSON obj = do
[x, y] <- parseJSON obj
return $ DataPoint x y
instance FromJSON Series where
parseJSON (Object o) = do
pts <- o .: "series"
fmap Series $ parseJSON pts
parseJSON _ = mzero这比我原来的答案要简单得多。向麦克斯致敬。
https://stackoverflow.com/questions/24742872
复制相似问题