我試圖從RESTful API中解析JSON。返回的JSON高度嵌套,可能/可能不包含某些字段。下面是一些例子返回的數據:用Aeson解析Haskell中的嵌套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模式與含有location
,arrival
,並queryTime
一個resultSet
開始。 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)))
顯示原始JSON但是,當我試圖讓ResultSet中的數據,它失敗Nothing
。
putStrLn (show (decode json :: Maybe ResultSet))
但是,如果我刪除嵌套數據,而只是試圖讓queryString
場(由FromJSON的數據類型,例如刪除字段,它成功並返回查詢字符串場。
data ResultSet
= ResultSet {
queryTime :: String
} deriving Show
instance FromJSON ResultSet where
parseJSON (Object o)
= ResultSet <$> ((o .: "resultSet") >>= (.: "queryTime"))
parseJSON _ = mzero
我在做什麼錯?這是在Haskell中解析JSON最簡單的方法嗎?我是這個(學生)的總noob,所以請保持溫柔
這個問題可能是,要麼你的解析器有一些錯誤或輸入並不像你想象的那樣。您應該嘗試使用anyDecode函數而不是解碼來獲取錯誤消息並將其粘貼到此處。 – Reite
樣式點:在ResultSet的parseJSON中,您應該提取ResultSet一次,然後詢問它。您正在爲相同的值進行三次單獨查找。 –
@Reite:使用任一代碼確實揭示了一個mzero錯誤。這告訴我,我的FromJSON實例是不正確的。它看起來像我的模式匹配正在落入'parseJSON _ = mzero'模式。但爲什麼?我已經檢查了傳入的JSON。位置字段在那裏。 –