如何允许阵列单个元素在保留其他元素的同时无法解析?

时间:2015-07-27 02:44:56

标签: haskell aeson

我有一个表现不佳的json源代码。它经常提供包含格式错误的数组元素的意外JSON。我想解析这个JSON并忽略任何格式错误的数组元素。

这是我的尝试:

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Control.Applicative        ((<$>), (<*>))
import Control.Monad              (mzero)
import Data.Aeson
import Data.ByteString.Lazy.Char8 (ByteString, pack)

data Foo = Foo Integer [Maybe Bar] deriving (Show)
data Bar = Bar Integer Integer deriving (Show)

instance FromJSON Foo where
    parseJSON (Object v) = Foo <$> (v .: "a") <*> (v .: "b") 
    parseJSON _          = mzero

instance FromJSON Bar where
    parseJSON (Object v) = Bar <$> (v .: "c") <*> (v .: "d")
    parseJSON _          = mzero

-- this string is malformed - second array element has an unexpected key
testString = pack "{\"a\":1, \"b\":[{\"c\":11, \"d\":12}, {\"C\":21, \"d\":22}, {\"c\":31, \"d\":32}]}"

-- want this to be: 
--
-- Just (Foo 1 [Just (Bar 11 12),Nothing,Just (Bar 31 32)])
--
-- or
--
-- Just (Foo 1 [Just (Bar 11 12),Just (Bar 31 32)])
main = print $ (decode testString :: Maybe Foo)

teststring格式错误时,Foo的整个解码将返回Nothing。我希望Foo解析,但b的任何格式错误的数组元素都是Nothing

1 个答案:

答案 0 :(得分:4)

您不能依赖FromJSON列表的默认实现,您必须自己做更多的工作:

instance FromJSON Foo where
    parseJSON (Object v) = do
        a <- v .: "a"
        bList <- v .: "b"
        return $ Foo a $ map (parseMaybe parseJSON) bList

parseMaybe parseJSON函数的类型为FromJSON a => Value -> Maybe a,因此bList :: [Value]表示map (parseMaybe parseJSON) bList :: [Maybe Bar]。这可能是考虑the documentation(参见&#34;解码混合类型对象&#34;)的最佳方法,它使用类似的方法来解析JSON,但表现不佳。