Haskell Aeson 解析混合元素数组
Haskell Aeson Parse Mixed Elements Array
我有一个 json 喜欢:
{
"name" : "Sam",
"items": [ "sword", "shield", [] ]
}
和数据类型
data Adventurer = Adventurer {
name :: String,
items :: [String]
} deriving (Generic, Show, FromJSON, ToJSON)
问题是因为 "items" 字段在数组中有多余的 [] 而我得到 "expected String, encountered Array".
我一直在尝试使用 "items" 数组元素的自定义数据类型来解决这个问题,或者尝试创建一个自定义解析器来忽略额外的数组。
有没有办法解析一个数组,只取特定类型的项目,丢弃其余的?
是的,例如我们可以首先构造一个函数,将 Value
s(这些是 JSON 对象)映射到 Maybe String
s:
import Data.Aeson(Value(String))
import Data.Text(unpack)
getString :: Value -> Maybe String
getString (String t) = Just (unpack t)
getString _ = Nothing
然后我们可以为 Adventurer
定义 FromJOSN
的自定义实现,例如:
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson(FromJSON(parseJSON), withObject, (.:))
import Data.Maybe(catMaybes)
instance FromJSON Adventurer where
parseJSON = withObject "Adventurer" $ \v -> Adventurer
<$> v .: "name"
<*> fmap (catMaybes . map getString) (v .: "items")
这会产生例如:
Main> t = "{\n \"name\" : \"Sam\",\n \"items\": [ \"sword\", \"shield\", [] ]\n}"
Main> decode t :: Maybe Adventurer
Just (Adventurer {name = "Sam", items = ["sword","shield"]})
我有一个 json 喜欢:
{
"name" : "Sam",
"items": [ "sword", "shield", [] ]
}
和数据类型
data Adventurer = Adventurer {
name :: String,
items :: [String]
} deriving (Generic, Show, FromJSON, ToJSON)
问题是因为 "items" 字段在数组中有多余的 [] 而我得到 "expected String, encountered Array".
我一直在尝试使用 "items" 数组元素的自定义数据类型来解决这个问题,或者尝试创建一个自定义解析器来忽略额外的数组。
有没有办法解析一个数组,只取特定类型的项目,丢弃其余的?
是的,例如我们可以首先构造一个函数,将 Value
s(这些是 JSON 对象)映射到 Maybe String
s:
import Data.Aeson(Value(String))
import Data.Text(unpack)
getString :: Value -> Maybe String
getString (String t) = Just (unpack t)
getString _ = Nothing
然后我们可以为 Adventurer
定义 FromJOSN
的自定义实现,例如:
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson(FromJSON(parseJSON), withObject, (.:))
import Data.Maybe(catMaybes)
instance FromJSON Adventurer where
parseJSON = withObject "Adventurer" $ \v -> Adventurer
<$> v .: "name"
<*> fmap (catMaybes . map getString) (v .: "items")
这会产生例如:
Main> t = "{\n \"name\" : \"Sam\",\n \"items\": [ \"sword\", \"shield\", [] ]\n}"
Main> decode t :: Maybe Adventurer
Just (Adventurer {name = "Sam", items = ["sword","shield"]})