使用 Aeson 解析嵌套数组和对象
Parsing nested arrays and objects with Aeson
我在编写 FromJSON
实例来解析包含嵌套在另一个对象数组中的对象数组的 JSON 文件时遇到问题。该文件的格式为:
[{"family":[{"name":"Jane","age":31,}
,{"name":"Ana","age":15,}]}
,{"family":[{"name":"Julia","age":45}
,{"name":"Chris","age":47}]}]
为此我创建了两个新类型:
-- A person
data Person = Person { name :: String
, age :: Int} deriving (Show, Eq)
-- A family is a list of list of Person
newtype Family = Family {unFamily :: [[Person]]} deriving (Show, Eq)
它们的实例是这些(使用 XOverloadedStrings
、aeson
和 text
):
instance ToJSON Person where
toJSON (Person n a) = object [ "name" .= n
, "age" .= a]
instance FromJSON Person where
parseJSON (Object o) = Person
<$> o .:? "name" .!= ""
<*> o .:? "age" .!= 0
parseJSON _ = mzero
instance ToJSON Family where
toJSON (Family c) = toJSON . map (\v -> object $ ("family",v):[])
$ map toJSON c
我可以做一些测试(加载 bytestring
和 maybe
)
> julia = Person "Julia" 45
> (== julia) . fromMaybe (Person "" 0) . decode . encode $ julia
True
> BS.putStrLn . BL.toStrict . encode $ Family [[julia,julia],[julia]]
[{"family":[{"age":45,"name":"Julia"},{"age":45,"name":"Julia"}]},{"family":[{"age":45,"name":"Julia"}]}]
一切都如我所愿。但正如我所说,我不能写 FromJSON Family
,所以我不能像 decode . encode
那样测试 julia
。
我查看了 aeson
中涉及的许多类型,试图找到一种方法让它发挥作用,但我就是做不到。我至少可以为 ToJSON Family
写 toJSON
因为我了解到 type Pair = (Text, Value)
.
谁能给我指明方向?有没有更好的写法 ToJSON Family
?
我会写
newtype Family = Family {unFamily :: [Person]}
相反。那么
instance FromJSON Family where
parseJSON (Object o) = Family <$> (o .: "family")
parseJSON v = typeMismatch "family" v
instance ToJSON Family where
toJSON (Family c) = "family" .= c
应该对实例起作用,而您为 [Family]
免费获得的 FromJSON
/ToJSON
实例将解码您展示的示例 JSON us/encode 您向我们展示的示例家庭。
你可以创建一个解析子列表的函数,然后使用mapM
转换子列表:
import Data.Foldable(toList)
instance FromJSON Family where
parseJSON (Array arr) = Family <$> mapM parseSubList (toList arr)
where parseSubList (Object o) = o .:? "family" .!= []
例如:
Prelude Data.Aeson Data.Foldable> decode "[{\"family\":[{\"age\":45,\"name\":\"Julia\"},{\"age\":45,\"name\":\"Julia\"}]},{\"family\":[{\"age\":45,\"name\":\"Julia\"}]}]" :: Maybe Family
Just (Family {unFamily = [[Person {name = "Julia", age = 45},Person {name = "Julia", age = 45}],[Person {name = "Julia", age = 45}]]})
我在编写 FromJSON
实例来解析包含嵌套在另一个对象数组中的对象数组的 JSON 文件时遇到问题。该文件的格式为:
[{"family":[{"name":"Jane","age":31,}
,{"name":"Ana","age":15,}]}
,{"family":[{"name":"Julia","age":45}
,{"name":"Chris","age":47}]}]
为此我创建了两个新类型:
-- A person
data Person = Person { name :: String
, age :: Int} deriving (Show, Eq)
-- A family is a list of list of Person
newtype Family = Family {unFamily :: [[Person]]} deriving (Show, Eq)
它们的实例是这些(使用 XOverloadedStrings
、aeson
和 text
):
instance ToJSON Person where
toJSON (Person n a) = object [ "name" .= n
, "age" .= a]
instance FromJSON Person where
parseJSON (Object o) = Person
<$> o .:? "name" .!= ""
<*> o .:? "age" .!= 0
parseJSON _ = mzero
instance ToJSON Family where
toJSON (Family c) = toJSON . map (\v -> object $ ("family",v):[])
$ map toJSON c
我可以做一些测试(加载 bytestring
和 maybe
)
> julia = Person "Julia" 45
> (== julia) . fromMaybe (Person "" 0) . decode . encode $ julia
True
> BS.putStrLn . BL.toStrict . encode $ Family [[julia,julia],[julia]]
[{"family":[{"age":45,"name":"Julia"},{"age":45,"name":"Julia"}]},{"family":[{"age":45,"name":"Julia"}]}]
一切都如我所愿。但正如我所说,我不能写 FromJSON Family
,所以我不能像 decode . encode
那样测试 julia
。
我查看了 aeson
中涉及的许多类型,试图找到一种方法让它发挥作用,但我就是做不到。我至少可以为 ToJSON Family
写 toJSON
因为我了解到 type Pair = (Text, Value)
.
谁能给我指明方向?有没有更好的写法 ToJSON Family
?
我会写
newtype Family = Family {unFamily :: [Person]}
相反。那么
instance FromJSON Family where
parseJSON (Object o) = Family <$> (o .: "family")
parseJSON v = typeMismatch "family" v
instance ToJSON Family where
toJSON (Family c) = "family" .= c
应该对实例起作用,而您为 [Family]
免费获得的 FromJSON
/ToJSON
实例将解码您展示的示例 JSON us/encode 您向我们展示的示例家庭。
你可以创建一个解析子列表的函数,然后使用mapM
转换子列表:
import Data.Foldable(toList)
instance FromJSON Family where
parseJSON (Array arr) = Family <$> mapM parseSubList (toList arr)
where parseSubList (Object o) = o .:? "family" .!= []
例如:
Prelude Data.Aeson Data.Foldable> decode "[{\"family\":[{\"age\":45,\"name\":\"Julia\"},{\"age\":45,\"name\":\"Julia\"}]},{\"family\":[{\"age\":45,\"name\":\"Julia\"}]}]" :: Maybe Family
Just (Family {unFamily = [[Person {name = "Julia", age = 45},Person {name = "Julia", age = 45}],[Person {name = "Julia", age = 45}]]})