带有数组数组的Aeson,其中一些是空的

时间:2017-10-17 00:10:07

标签: haskell aeson

我有不幸的数据可供使用:

{ "name": "foo"
, "data": [ []
          , ["a", "b", "c", 1]
          , ["d", "e", "f", 2] ] }

允许数据条目为空数组或大小为4的数组。

我想解析:

data ResultRow = ResultRow Text Text Text Int deriving (Show, Generic)

data ResultSet =
  ResultSet { f_name :: Text
            , f_data :: [Maybe ResultRow] } deriving (Show, Generic)

然而,以下内容不接受空数组:

customOptions = defaultOptions { fieldLabelModifier = drop 2 }

instance FromJSON ResultRow where
  parseJSON = genericParseJSON customOptions
instance FromJSON ResultSet where
  parseJSON = genericParseJSON customOptions

错误消息是:

Left "Error in $[1].data[0]: When expecting a product of 4 values, encountered an Array of 0 elements instead"

我还尝试在[Maybe ResultRow]周围添加一个额外的类型,并将子数组转换为[]上的列表和模式匹配,并将非空案例分派给{{1}解析器,但我根本无法编译并迷失在错误消息中。

理想情况下,我想有一些方法可以跳过空数组,因为它们只是数据中的噪音。我无法控制数据的制作者。

1 个答案:

答案 0 :(得分:3)

dsvensson 一样,我感到困惑的是,这并不适合 dsvensson'开箱即用,因为当[a]时,Maybe aFromJSON都是a个实例。由于我已经花费了太多时间在这上面,我无法提供解释,但我可以提供解决方法。希望有更多知识渊博的人可以给出更好的答案。

您可以定义包裹f_data的{​​{1}},而不是将[Maybe ResultRow]定义为newtype

Maybe ResultRow

您可以为此类型提供特殊的newtype MaybeResultRow = MaybeResultRow (Maybe ResultRow) deriving (Show, Generic) 行为:

FromJSON

这显然意味着instance FromJSON MaybeResultRow where parseJSON v = case fromJSON v of Success rr -> return $ MaybeResultRow $ Just rr _ -> return $ MaybeResultRow Nothing

的变化
ResultSet

为了测试,我定义了这个JSON文档:

data ResultSet =
  ResultSet { f_name :: Text
            , f_data :: [MaybeResultRow] } deriving (Show, Generic)

将它们全部加载到GHCi中,它看起来像是在工作:

myJson :: ByteString
myJson =
  "{\
     \\"name\": \"foo\",\
     \\"data\": [\
        \[],\
        \[\"a\", \"b\", \"c\", 1],\
        \[\"d\", \"e\", \"f\", 2]\
     \]\
   \}"

在这里,我冒昧地格式化GHCi的输出,以提高可读性。

我相信您可以弄清楚如何打开和过滤*Lib Lib> decode myJson :: Maybe ResultSet Just (ResultSet { f_name = "foo" , f_data = [ MaybeResultRow Nothing, MaybeResultRow (Just (ResultRow "a" "b" "c" 1)), MaybeResultRow (Just (ResultRow "d" "e" "f" 2))]}) 值列表......

我偷了使用MaybeResultRow的解决方案,并在this answerfromJSON上进行了匹配。