我一直在努力尝试使用 Aeson 来解析 Bitly 的响应。有人可以给我一个关于应该定义哪些 Haskell 类型以及如何使用 Aeson 将以下内容解析为这些类型的提示吗?:
// BITLY EXPAND RESPONSE
{
"data": {
"expand": [
{
"global_hash": "900913",
"long_url": "http://google.com/",
"short_url": "http://bit.ly/ze6poY",
"user_hash": "ze6poY"
}
]
},
"status_code": 200,
"status_txt": "OK"
}
// BITLY SHORTEN RESPONSE
{
"data": {
"global_hash": "900913",
"hash": "ze6poY",
"long_url": "http://google.com/",
"new_hash": 0,
"url": "http://bit.ly/ze6poY"
},
"status_code": 200,
"status_txt": "OK"
}
这是我到目前为止所尝试的:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
module BitlyClientResponses where
import Control.Applicative
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as L (pack)
import qualified Data.HashMap.Strict as M
data DataStatusCodeStatusTxt =
DSCST { ddata :: ResponseData
, status_code :: Integer
, status_txt :: String
}
deriving (Eq, Show)
data ResponseData
= ExpandResponseData { expand :: [Response]
}
deriving (Eq, Show)
data Response = ExpandResponse { long_url :: String -- URI
, global_hash :: String
, short_url :: String -- URI
, user_hash :: String
-- , hash :: [String]
-- , error :: String
}
| J String
| N String
deriving (Eq, Show)
instance FromJSON DataStatusCodeStatusTxt where
parseJSON (Object o) = DSCST <$>
o .: "data" <*>
o .: "status_code" <*>
o .: "status_txt"
parseJSON x = fail $ "FAIL: DataStatusCodeStatusTxt: " ++ (show x)
instance FromJSON ResponseData where
parseJSON (Object o) =
case M.lookup "expand" o of
-- LOST RIGHT HERE
Just v -> return $ ExpandResponseData [J ((show o) ++ " $$$ " ++ (show v))]
Nothing -> return $ ExpandResponseData [N "N"]
parseJSON x = fail $ "FAIL: ResponseData: " ++ (show x)
instance FromJSON Response where
parseJSON (Object o) = ExpandResponse <$>
o .: "long_url" <*>
o .: "global_hash" <*>
o .: "short_url" <*>
o .: "user_hash"
-- o .: "hash" <*>
-- o .: "error" <*>
parseJSON x = fail $ "FAIL: Response: " ++ (show x)
parseResponse :: String -> Either String DataStatusCodeStatusTxt
parseResponse x = eitherDecode $ L.pack x
当我输入时(为便于阅读而手工编辑):
"{ \"status_code\": 200,
\"status_txt\": \"OK\",
\"data\": { \"expand\": [
{ \"short_url\": \"http:\\/\\/bit.ly\\/LCJq0b\",
\"long_url\": \"http:\\/\\/blog.swisstech.net\\/2012\\/06\\/local-postfix-as-relay-to-amazon-ses.html\",
\"user_hash\": \"LCJq0b\",
\"global_hash\": \"LCJsVy\" }, ...
我回来了(也手工编辑):
Right
(Right
(DSCST
{ddata = ExpandResponseData {expand = [J "fromList [(\"expand\",Array (fromList [Object fromList [(\"long_url\",String \"http://blog.swisstech.net/2012/06/local-postfix-as-relay-to-amazon-ses.html\"),(\"global_hash\",String \"LCJsVy\"),(\"short_url\",String \"http://bit.ly/LCJq0b\"),(\"user_hash\",String \"LCJq0b\")], ...
$$$
Array (fromList [Object fromList [(\"long_url\",String \"http://blog.swisstech.net/2012/06/local-postfix-as-relay-to-amazon-ses.html\"),(\"global_hash\",String \"LCJsVy\"),(\"short_url\",String \"http://bit.ly/LCJq0b\"),(\"user_hash\",String \"LCJq0b\")], ...
在代码中,查找-- LOST RIGHT HERE
. 我不知道如何解析"expand"
.
很高兴看到如何取得进展。也许我走错了路,有人可以让我直截了当(例如,我到目前为止定义的数据类型可能是关闭的)。