Aeson 没有找到我认为存在的钥匙
Aeson does not find a key that I believe is present
我正在尝试解析如下所示的 JSON blob:
"{\"order_book\":{\"asks\":[[\"0.06777\",\"0.00006744\"],[\"0.06778\",\"0.01475361\"], ... ]],\"bids\":[[\"0.06744491\",\"1.35\"],[\"0.06726258\",\"0.148585363\"], ...]],\"market_id\":\"ETH-BTC\"}}"
那些数字对的列表实际上要长得多;我用省略号替换了它们的尾巴。
这是我的代码:
{-# LANGUAGE OverloadedStrings #-}
module Demo where
import Data.Aeson
import Data.ByteString.Lazy hiding (putStrLn)
import Data.Either (fromLeft)
import Network.HTTP.Request
data OrderBook = OrderBook
{ orderBook_asks :: [[(Float,Float)]]
, orderBook_bids :: [[(Float,Float)]]
, orderBook_marketId :: String
}
instance FromJSON OrderBook where
parseJSON = withObject "order_book" $ \v -> OrderBook
<$> v .: "asks"
<*> v .: "bids"
<*> v .: "market_id"
demo :: IO ()
demo = do
r <- get "https://www.buda.com/api/v2/markets/eth-btc/order_book"
let d = eitherDecode $ fromStrict $ responseBody r :: Either String OrderBook
putStrLn $ "Here's the parse error:"
putStrLn $ fromLeft undefined d
putStrLn $ "\n\nAnd here's the data:"
putStrLn $ show $ responseBody r
这是 运行 demo
让我明白的:
Here's the parse error:
Error in $: key "asks" not found
And here's the data:
"{\"order_book\":{\"asks\":[[\"0.06777\",\"0.00006744\"],[\"0.06778\",\"0.01475361\"], ... ]],\"bids\":[[\"0.06744491\",\"1.35\"],[\"0.06726258\",\"0.148585363\"], ...]],\"market_id\":\"ETH-BTC\"}}"
“询问”键看起来很清楚——它是第一个嵌套在“order_book”键下的键。
密钥存在,但它被包裹在另一个嵌套对象中,因此您必须先打开外部对象才能解析密钥。
执行此操作的 smallest-diff 方法可能只是内联:
instance FromJSON OrderBook where
parseJSON = withObject "order_book" $ \outer -> do
v <- outer .: "order_book"
OrderBook
<$> v .: "asks"
<*> v .: "bids"
<*> v .: "market_id"
尽管您可能想考虑引入另一种包装类型。这实际上取决于您拥有的数据格式的语义。
我猜你可能假设这是 withObject "order_book"
会做的,但事实并非如此。 withObject
的第一个参数只是被解析对象的 human-readable 名称,用于创建错误消息。通常该参数应命名正在解析的 type - 即 withObject "OrderBook"
。 See the docs.
另外,我认为您的 asks
和 bids
字段输入错误。
首先,您的 JSON 输入看起来应该是元组数组,但您的 Haskell 类型表示 双重嵌套 元组数组。所以这将无法解析。
其次,您的 JSON 输入包含字符串作为这些元组的元素,但您的 Haskell 类型表示 Float
。这也将无法解析。
根据您的 JSON 输入,正确的类型应该是:
{ orderBook_asks :: [(String,String)]
, orderBook_bids :: [(String,String)]
或者,如果您真的想要浮点数,则必须从字符串中解析它们:
instance FromJSON OrderBook where
parseJSON = withObject "order_book" $ \outer -> do
v <- outer .: "order_book"
OrderBook
<$> (map parseTuple <$> v .: "asks")
<*> (map parseTuple <$> v .: "bids")
<*> v .: "market_id"
where
parseTuple (a, b) = (read a, read b)
(注意这个 ☝️ 代码不能被复制和粘贴:我正在使用 read
将字符串解析为浮点数,如果字符串格式不正确,它会在运行时崩溃;在实际程序中你应该使用更好的解析方式)
withObject "order_book"
不查看键 "order_book"
处的值。事实上, "order_book"
参数除了出现在错误消息中外,被忽略了;实际上你应该有 withObject "OrderBook"
那里。
所有 withObject
所做的就是确认您拥有的 是 一个对象。然后它继续使用该对象查找键 "asks"
、"bids"
和 "market_id"
– 但在这一层唯一的键是 order_book
.
解决方案是仅将此解析器与 {"asks":[["0.06777"...]...]...}
对象一起使用。 "order_book"
键无论如何都不会告诉任何信息,除非那里也存在其他键。您可以用另一个 Haskell 类型和它自己的 FromJSON
实例来表示该外部对象。
我正在尝试解析如下所示的 JSON blob:
"{\"order_book\":{\"asks\":[[\"0.06777\",\"0.00006744\"],[\"0.06778\",\"0.01475361\"], ... ]],\"bids\":[[\"0.06744491\",\"1.35\"],[\"0.06726258\",\"0.148585363\"], ...]],\"market_id\":\"ETH-BTC\"}}"
那些数字对的列表实际上要长得多;我用省略号替换了它们的尾巴。
这是我的代码:
{-# LANGUAGE OverloadedStrings #-}
module Demo where
import Data.Aeson
import Data.ByteString.Lazy hiding (putStrLn)
import Data.Either (fromLeft)
import Network.HTTP.Request
data OrderBook = OrderBook
{ orderBook_asks :: [[(Float,Float)]]
, orderBook_bids :: [[(Float,Float)]]
, orderBook_marketId :: String
}
instance FromJSON OrderBook where
parseJSON = withObject "order_book" $ \v -> OrderBook
<$> v .: "asks"
<*> v .: "bids"
<*> v .: "market_id"
demo :: IO ()
demo = do
r <- get "https://www.buda.com/api/v2/markets/eth-btc/order_book"
let d = eitherDecode $ fromStrict $ responseBody r :: Either String OrderBook
putStrLn $ "Here's the parse error:"
putStrLn $ fromLeft undefined d
putStrLn $ "\n\nAnd here's the data:"
putStrLn $ show $ responseBody r
这是 运行 demo
让我明白的:
Here's the parse error:
Error in $: key "asks" not found
And here's the data:
"{\"order_book\":{\"asks\":[[\"0.06777\",\"0.00006744\"],[\"0.06778\",\"0.01475361\"], ... ]],\"bids\":[[\"0.06744491\",\"1.35\"],[\"0.06726258\",\"0.148585363\"], ...]],\"market_id\":\"ETH-BTC\"}}"
“询问”键看起来很清楚——它是第一个嵌套在“order_book”键下的键。
密钥存在,但它被包裹在另一个嵌套对象中,因此您必须先打开外部对象才能解析密钥。
执行此操作的 smallest-diff 方法可能只是内联:
instance FromJSON OrderBook where
parseJSON = withObject "order_book" $ \outer -> do
v <- outer .: "order_book"
OrderBook
<$> v .: "asks"
<*> v .: "bids"
<*> v .: "market_id"
尽管您可能想考虑引入另一种包装类型。这实际上取决于您拥有的数据格式的语义。
我猜你可能假设这是 withObject "order_book"
会做的,但事实并非如此。 withObject
的第一个参数只是被解析对象的 human-readable 名称,用于创建错误消息。通常该参数应命名正在解析的 type - 即 withObject "OrderBook"
。 See the docs.
另外,我认为您的 asks
和 bids
字段输入错误。
首先,您的 JSON 输入看起来应该是元组数组,但您的 Haskell 类型表示 双重嵌套 元组数组。所以这将无法解析。
其次,您的 JSON 输入包含字符串作为这些元组的元素,但您的 Haskell 类型表示 Float
。这也将无法解析。
根据您的 JSON 输入,正确的类型应该是:
{ orderBook_asks :: [(String,String)]
, orderBook_bids :: [(String,String)]
或者,如果您真的想要浮点数,则必须从字符串中解析它们:
instance FromJSON OrderBook where
parseJSON = withObject "order_book" $ \outer -> do
v <- outer .: "order_book"
OrderBook
<$> (map parseTuple <$> v .: "asks")
<*> (map parseTuple <$> v .: "bids")
<*> v .: "market_id"
where
parseTuple (a, b) = (read a, read b)
(注意这个 ☝️ 代码不能被复制和粘贴:我正在使用 read
将字符串解析为浮点数,如果字符串格式不正确,它会在运行时崩溃;在实际程序中你应该使用更好的解析方式)
withObject "order_book"
不查看键 "order_book"
处的值。事实上, "order_book"
参数除了出现在错误消息中外,被忽略了;实际上你应该有 withObject "OrderBook"
那里。
所有 withObject
所做的就是确认您拥有的 是 一个对象。然后它继续使用该对象查找键 "asks"
、"bids"
和 "market_id"
– 但在这一层唯一的键是 order_book
.
解决方案是仅将此解析器与 {"asks":[["0.06777"...]...]...}
对象一起使用。 "order_book"
键无论如何都不会告诉任何信息,除非那里也存在其他键。您可以用另一个 Haskell 类型和它自己的 FromJSON
实例来表示该外部对象。