使用 lens-aeson 从 JSON ByteString 获取值的集合

Getting a collection of values from a JSON ByteString using lens-aeson

假设我有一个 JSON ByteString 看起来像

{
    messages: [
        {...},
        {...}
    ]
}

我想使用镜头从中获取 list/vector 条消息。我有一个函数 toMessage 可以将 Value 变成 Maybe Message.

我试过这个作文key "messages" . values . to toMessageto来自Control.Lens.Getter,但结果是Maybe Message,它只是变成了Nothing

目前我正在做这个

msgsJson <- c ^? key "messages"
let msgs = toList $ mapMaybe message $ msgsJson ^.. values

mapMaybe来自witherabletoList是将Vector转换成列表) 但我想知道是否有一种方法可以组合各种镜头来获得一个镜头来做到这一点。

嗯,这对我有用:

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Data.ByteString (ByteString)

import Control.Lens
import Data.Aeson
import Data.Aeson.Lens

newtype Message =
  Message Integer
  deriving (Show)

toMessage :: Value -> Maybe Message
toMessage json_ = do
  i <- json_ ^? key "a" . _Integer
  return (Message i)

input :: ByteString
input = "{\"messages\":[{\"a\":1},{\"a\":2},{\"a\":3}]}"

main :: IO ()
main =
  print (input ^.. (key "messages" . values . to toMessage))
λ> main
[Just (Message 1),Just (Message 2),Just (Message 3)]

如果您得到 Nothing,这可能意味着您的 JSON 无效(您可以使用 decode json :: Maybe Value 进行测试)。或者组合中的任何其他光学元件都失效了。对于长点状光学元件,有时很难准确判断出哪个元件出现故障,除非将末端的零件切掉并重试。但是你的组合光学 key "messages" . values . to toMessage 应该 Just Work™。

顺便说一句:

msgJson <- c ^? key "messages"
let msgs = toList $ mapMaybe message $ msgsJson ^.. values

应该和

一样
msgJson <- c ^? key "messages"
let msgs = toList $ msgsJson ^.. (values . to message . _Just)

msgJson <- c ^? key "messages"
let msgs = msgsJson ^.. (values . to message . _Just)

let msgs = c ^.. (key "messages" . values . to message . _Just)