使用Aeson解析JSON对象数组时跳过指定项的实现方法
解决JSON数组解析时跳过指定元素的问题
你的核心问题在于:原代码中使用mapM parseJSON arr时,只要数组内有一个元素解析失败(遇到exclude: true触发mzero),整个Response的解析就会直接失败,而非跳过该元素。要实现跳过逻辑,需要在Response的解析层将单个元素的解析结果转为Maybe类型,过滤掉失败的Nothing项即可。
下面提供两种可行的实现方案:
方案1:使用optional在Parser Monad内处理
利用Control.Applicative中的optional函数,将单个元素的解析结果从Parser Foo转为Parser (Maybe Foo)——解析失败时返回Nothing,成功时返回Just Foo,最后过滤掉Nothing得到有效列表。
import Data.Aeson (FromJSON(..), withArray, withObject, (.)) import Data.Text (Text) import Control.Applicative (optional) import Data.Maybe (catMaybes) newtype Response = Response [Foo] newtype Foo = Foo Text instance FromJSON Response where parseJSON = withArray "Foos" $ \arr -> do -- 将每个元素的解析结果转为Maybe,失败则为Nothing maybeFoos <- traverse (optional . parseJSON) arr -- 过滤掉Nothing,保留有效Foo pure $ Response (catMaybes (toList maybeFoos)) instance FromJSON Foo where parseJSON = withObject "Foo" $ \foo -> do isExcluded <- foo .: "exclude" if isExcluded then mzero -- 标记为失败 else pure $ Foo "bar"
方案2:使用parseMaybe纯函数处理
直接用Data.Aeson提供的parseMaybe函数,将数组中的每个Value直接转为Maybe Foo,再过滤掉Nothing项。
import Data.Aeson (FromJSON(..), withArray, withObject, (.:), parseMaybe) import Data.Text (Text) import Data.Maybe (catMaybes) newtype Response = Response [Foo] newtype Foo = Foo Text instance FromJSON Response where parseJSON = withArray "Foos" $ \arr -> do -- 逐个尝试解析元素,失败得到Nothing let maybeFoos = map (parseMaybe parseJSON) (toList arr) -- 过滤无效项,构建Response pure $ Response (catMaybes maybeFoos) instance FromJSON Foo where parseJSON = withObject "Foo" $ \foo -> do isExcluded <- foo .: "exclude" if isExcluded then mzero else pure $ Foo "bar"
两种方案都能实现你的需求:跳过所有带有exclude: true的对象,只保留有效解析的Foo元素。区别在于optional是在Parser Monad内部处理失败逻辑,而parseMaybe是通过纯函数直接转换结果,可根据代码风格偏好选择。
内容的提问来源于stack exchange,提问作者dimsuz
相关产品推荐
相关产品推荐

