如何在GHCI中便捷访问JSON字段,无需定义完整对应数据结构?
你遇到的类型错误本质是因为!运算符从Object中取出的值是Value类型,它可以是任意JSON类型(对象、数组、字符串、数字等),无法直接当做数组调用!!,也无法直接当做对象继续取值,必须先完成类型校验和转换。
方案1:使用lens-aeson实现类Python链式访问(推荐)
这种方式语法最简洁,和Python的链式访问体验最接近,不需要定义任何自定义数据类型:
首先需要引入依赖:aeson、lens-aeson,导入对应模块:
import Data.Aeson.Lens (key, nth, _String, _Array, _Object) import Control.Lens ((^?), filtered) import Data.Text (unpack)
提取ISBN的代码如下:
-- 安全取值,返回 Maybe String,任意节点缺失都会返回 Nothing let isbn = body ^? key "items" . nth 0 . key "volumeInfo" . key "industryIdentifiers" . _Array . traverse . _Object . filtered (\o -> o ^? key "type" . _String == Just "ISBN_10") . key "identifier" . _String . fmap unpack
如果需要和你写的Python代码一样,找不到值就直接抛出异常,可以把^?替换为^?!。
方案2:使用aeson原生API手动解析(无额外依赖)
如果不想引入lens相关依赖,也可以直接用aeson自带的解析器组合实现,同样不需要定义完整JSON结构:
import Data.Aeson (withObject, withArray, withText, (.:), FromJSON(..)) import Data.Vector (toList, (!)) import Data.Either (either) import Data.Text (unpack) getISBN10 :: Object -> Maybe String getISBN10 body = either (const Nothing) Just $ parseJSON isbnParser (Object body) where isbnParser = withObject "responseBody" $ \o -> do items <- o .: "items" >>= withArray "itemsList" pure firstItem <- parseJSON (items ! 0) >>= withObject "firstItem" pure volumeInfo <- firstItem .: "volumeInfo" identifiers <- volumeInfo .: "industryIdentifiers" >>= withArray "idList" (pure . toList) let findISBN [] = fail "ISBN_10 not found" findISBN (idVal:rest) = do idObj <- withObject "identifier" pure idVal idType <- idObj .: "type" if idType == "ISBN_10" then idObj .: "identifier" >>= withText "isbnVal" (pure . unpack) else findISBN rest findISBN identifiers
调用getISBN10 body即可得到Maybe String类型的ISBN结果。
生产环境建议优先使用返回Maybe的安全接口,避免因JSON结构变化导致程序崩溃。
内容的提问来源于stack exchange,提问作者Jonathan
相关产品推荐
相关产品推荐

