如何使用Aeson的Parser从简单[Object]中按Key获取Value?
在Haskell中用Aeson解析JSON数组并按Key取值的问题
看起来你在处理JSON解析时遇到了点小麻烦——拿到[Object]类型的数组后,不知道怎么用字符串Key取出对应的值对吧?先拆解你遇到的报错原因,再给你可行的解决办法:
为什么之前的写法会报错?
- 尝试方案1:
d . key "test"首先语法就不对,key是Aeson-Lens提供的镜头,要访问值得用^.操作符;更关键的是,d是对象数组([Object]),key镜头是作用在**单个Object或Value**上的,不能直接套在数组上。 - 尝试方案2:
d ^. key "test"类型完全不匹配——d是[Object],key "test"期望的是单个对象,最终得到的是Value类型,但你的代码上下文期望的是Parser [Object],自然会触发类型不匹配的报错。
正确的处理方式
既然d是对象数组,核心思路就是遍历数组里的每个Object,再对单个对象提取指定Key的值。下面给你几种实用的写法:
方式1:用Aeson原生的.:解析字段
如果要从数组的每个对象里提取"test"字段(假设是字符串类型),可以直接用traverse遍历数组,对每个对象调用.::
parseResponse z = do result <- eitherDecode z flip parseEither result (\obj -> do d <- obj .: "data" -- 拿到[Object]类型的数组 -- 遍历每个Object,解析"test"字段为String testValues <- traverse (\singleObj -> singleObj .: "test") d return testValues )
方式2:结合Aeson-Lens提取值
如果想用lens的方式,需要注意key "test"返回的是Value,得用_String镜头提取字符串,同时要处理字段不存在或类型不匹配的情况:
parseResponse z = do result <- eitherDecode z flip parseEither result (\obj -> do d <- obj .: "data" -- 遍历数组,对每个Object用lens提取"test"对应的字符串 testValues <- traverse (\singleObj -> case singleObj ^? key "test" . _String of Just s -> pure s Nothing -> fail "Field 'test' not found or is not a string" ) d return testValues )
扩展:解析成自定义Job类型
你的代码里apiPendingJobs要返回[Job],如果给Job实现了FromJSON实例,直接遍历数组解析每个对象就行:
-- 先给Job实现FromJSON实例(示例,根据你的Job类型调整字段) instance FromJSON Job where parseJSON = withObject "Job" (\o -> Job <$> o .: "jobId" <*> o .: "status" <*> o .: "description" ) -- 修正parseResponse函数 parseResponse :: ByteString -> Either String [Job] parseResponse z = do result <- eitherDecode z flip parseEither result (\obj -> do d <- obj .: "data" -- 拿到[Object]数组 traverse parseJSON d -- 把每个Object解析成Job )
这样修改后,apiPendingJobs里调用parseResponse就能得到Either String [Job],后续可以处理这个结果返回正确的[Job]列表。
内容的提问来源于stack exchange,提问作者Chris Stryczynski
相关产品推荐
相关产品推荐

