gpt4 book ai didi

json - 使用 Aeson 在 Haskell 中解析嵌套 JSON

转载 作者:行者123 更新时间:2023-12-04 02:07:37 24 4
gpt4 key购买 nike

我正在尝试从 RESTful API 解析 JSON。返回的 JSON 是高度嵌套的,可能/可能不包含某些字段。以下是一些返回数据的示例:

{
resultSet : {
location : [{
desc : "Tuality Hospital/SE 8th Ave MAX Station",
locid : 9843,
dir : "Eastbound",
lng : -122.978016886765,
lat : 45.5212880911494
}
],
arrival : [{
detour : false,
status : "estimated",
locid : 9843,
block : 9024,
scheduled : "2014-03-02T16:48:15.000-0800",
shortSign : "Blue to Gresham",
dir : 0,
estimated : "2014-03-02T16:48:15.000-0800",
route : 100,
departed : false,
blockPosition : {
at : "2014-03-02T16:16:43.579-0800",
feet : 3821,
lng : -122.9909514,
trip : [{
progress : 171494,
desc : "Hatfield Government Center",
pattern : 140,
dir : 1,
route : 100,
tripNum : "4365647",
destDist : 171739
}, {
progress : 0,
desc : "Cleveland Ave",
pattern : 10,
dir : 0,
route : 100,
tripNum : "4365248",
destDist : 3577
}
],
lat : 45.5215368,
heading : 328
},
fullSign : "MAX Blue Line to Gresham",
piece : "1"
}, {
detour : false,
status : "estimated",
locid : 9843,
block : 9003,
scheduled : "2014-03-02T17:05:45.000-0800",
shortSign : "Blue to Gresham",
dir : 0,
estimated : "2014-03-02T17:05:45.000-0800",
route : 100,
departed : false,
blockPosition : {
at : "2014-03-02T16:34:33.787-0800",
feet : 3794,
lng : -122.9909918,
trip : [{
progress : 171521,
desc : "Hatfield Government Center",
pattern : 140,
dir : 1,
route : 100,
tripNum : "4365648",
destDist : 171739
}, {
progress : 0,
desc : "Cleveland Ave",
pattern : 10,
dir : 0,
route : 100,
tripNum : "4365250",
destDist : 3577
}
],
lat : 45.5216054,
heading : 345
},
fullSign : "MAX Blue Line to Gresham",
piece : "1"
}
],
queryTime : "2014-03-02T16:35:21.039-0800"
}
}

如您所见,JSON 模式以 resultSet 开头。其中包含 location , arrival , 和 queryTime . location反过来,包含位置列表 arrival包含到达列表和 queryTime只是一个UTC时间。然后,一个 arrival可以包含 blockPosition ,其中可以包含 trip等等。很多嵌套。很多可选字段。

为了掌握这一切,我创建了一组新的数据类型。数据类型嵌套类似。对于每种数据类型,我都有一个 FromJSON 实例(来自 Aeson 库)。
-- Data Type Definitions and FromJSON Instance Definitions ---------------------


data ResultSet
= ResultSet { locations :: LocationList
,arrivals :: ArrivalList
,queryTime :: String
} deriving Show

instance FromJSON ResultSet where
parseJSON (Object o) =
ResultSet <$> ((o .: "resultSet") >>= (.: "location"))
<*> ((o .: "resultSet") >>= (.: "arrival"))
<*> ((o .: "resultSet") >>= (.: "queryTime"))
parseJSON _ = mzero

data TripList = TripList {triplist :: [Trip]} deriving Show

instance FromJSON TripList where
parseJSON (Object o) =
TripList <$> (o .: "trip")
parseJSON _ = mzero

data LocationList = LocationList {locationList :: [Location]} deriving Show

instance FromJSON LocationList where
parseJSON (Object o) =
LocationList <$> (o .: "location")
parseJSON _ = mzero

data Location
= Location { loc_desc :: String
,loc_locid :: Int
,loc_dir :: String
,loc_lng :: Double
,loc_lat :: Double
} deriving Show

instance FromJSON Location where
parseJSON (Object o) =
Location <$> (o .: "desc")
<*> (o .: "locid")
<*> (o .: "dir")
<*> (o .: "lng")
<*> (o .: "lat")
parseJSON _ = mzero

data ArrivalList = ArrivalList {arrivalList :: [Arrival]} deriving Show

instance FromJSON ArrivalList where
parseJSON (Object o) =
ArrivalList <$> (o .: "arrival")
parseJSON _ = mzero

data Arrival
= Arrival { arr_detour :: Bool
,arr_status :: String
,arr_locid :: Int
,arr_block :: Int
,arr_scheduled :: String
,arr_shortSign :: String
,arr_dir :: Int
,estimated :: Maybe String
,route :: Int
,departed :: Bool
,blockPosition :: Maybe BlockPosition
,fullSign :: String
,piece :: String
} deriving Show

instance FromJSON Arrival where
parseJSON (Object o) =
Arrival <$> (o .: "detour")
<*> (o .: "status")
<*> (o .: "locid")
<*> (o .: "block")
<*> (o .: "scheduled")
<*> (o .: "shortSign")
<*> (o .: "dir")
<*> (o .:? "estimated")
<*> (o .: "route")
<*> (o .: "departed")
<*> (o .:? "blockPosition")
<*> (o .: "fullSign")
<*> (o .: "piece")
parseJSON _ = mzero

data BlockPosition
= BlockPosition { bp_at :: String
,bp_feet :: Int
,bp_lng :: Double
,bp_trip :: Trip
,bp_lat :: Double
,bp_heading :: Int
} deriving Show

instance FromJSON BlockPosition where
parseJSON (Object o) =
BlockPosition <$> (o .: "at")
<*> (o .: "feet")
<*> (o .: "lng")
<*> (o .: "trip")
<*> (o .: "lat")
<*> (o .: "heading")
parseJSON _ = mzero

data Trip
= Trip { trip_progress :: Int
,trip_desc :: String
,trip_pattern :: Int
,trip_dir :: Int
,trip_route :: Int
,trip_tripNum :: Int
,trip_destDist :: Int
} deriving Show

instance FromJSON Trip where
parseJSON (Object o) =
Trip <$> (o .: "progress")
<*> (o .: "desc")
<*> (o .: "pattern")
<*> (o .: "dir")
<*> (o .: "route")
<*> (o .: "tripNum")
<*> (o .: "destDist")
parseJSON _ = mzero

现在,问题是:检索数据很容易。我可以通过
json <- getJSON stopID
putStrLn (show (decode json :: (Maybe Value)))

但是当我尝试获取 ResultSet 数据时,它失败了 Nothing .
putStrLn (show (decode json :: Maybe ResultSet))

但是,如果我删除嵌套数据并尝试获取 queryString字段(通过从 FromJSON 的数据类型和实例中删除字段,它成功并返回 queryString 字段。
data ResultSet
= ResultSet {
queryTime :: String
} deriving Show

instance FromJSON ResultSet where
parseJSON (Object o)
= ResultSet <$> ((o .: "resultSet") >>= (.: "queryTime"))
parseJSON _ = mzero

我究竟做错了什么?这是在 Haskell 中解析 JSON 的最简单方法吗?我是这个(学生)的菜鸟,所以请温柔。

最佳答案

我解决了我的问题。我试图为返回的 JSON 对象列表创建数据类型。例如,对于位置数据,它作为位置列表返回:

resultSet : {
location : [{
desc : "Tuality Hospital/SE 8th Ave MAX Station",
locid : 9843,
dir : "Eastbound",
lng : -122.978016886765,
lat : 45.5212880911494
}
],

我正在设置 Arrivals包含 [Arrival] 列表的数据类型:
data ArrivalList     = ArrivalList  {arrivalList  :: [Arrival]}  deriving Show

然后,当我尝试解析 JSON 时,我试图将 ArrivalList 填充到我的 ResultSet 中,稍后用于解析其中的 JSON 数据。但是由于 ArrivalList 不是 JSON 对象,所以它失败了。

解决方法是不对列表使用自定义数据类型。相反,将列表分配给 JSON !Array 对象,稍后可以将其解析为自己的对象和子对象。
 data ResultSet
= ResultSet {
locations :: !Array
,arrivals :: !Array
,queryTime :: String
} deriving Show

把它们放在一起:
data ResultSet
= ResultSet {
locations :: !Array
,arrivals :: !Array
,queryTime :: String
} deriving Show

instance FromJSON ResultSet where
parseJSON (Object o) = ResultSet <$>
((o .: "resultSet") >>= (.: "location"))
<*> ((o .: "resultSet") >>= (.: "arrival"))
<*> ((o .: "resultSet") >>= (.: "queryTime"))
parseJSON _ = mzero

data Location
= Location { loc_desc :: String
,loc_locid :: Int
,loc_dir :: String
,loc_lng :: Double
,loc_lat :: Double
} deriving Show

instance FromJSON Location where
parseJSON (Object o) =
Location <$> (o .: "desc")
<*> (o .: "locid")
<*> (o .: "dir")
<*> (o .: "lng")
<*> (o .: "lat")
parseJSON _ = mzero

关于json - 使用 Aeson 在 Haskell 中解析嵌套 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22135923/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com