2

我怎样才能浏览大Aeson Values?我知道应该有一个我感兴趣的字符串嵌套在结构的某个地方。我怎样才能找到它?

到目前为止,我只知道如何查询构造函数并发现它是一个数组。我怎么能比这更深入呢?

> take 20 $ show bt
"Array (fromList [Obj"
4

1 回答 1

4

lens包具有用于检查诸如 JSON 之类的树状结构的有用功能Value。还有lens-aeson带有额外 JSON 特定功能的包。

import Data.Text
import Data.Aeson
import Data.Aeson.Lens (_Value,_String) -- this is from lens-aeson
import Data.Foldable (toList)

import Control.Lens (Fold,folding,universeOf,toListOf,paraOf,preview)

我们可以从定义一个提取给定 JSONFold的直接子级的镜头开始:ValuesValue

vchildren :: Fold Value Value
vchildren = folding $ \v -> case v of
    Object o -> toList o
    Array a -> toList a
    _ -> []

folding是一个函数,lens它创建一个Fold返回列表的函数。Value在我们的例子中是一个 s的列表。

我们可以结合vchildrenfromuniverseOf函数Control.Lens.Plated来获得一个提取 a 的所有传递后代的函数Value,包括它自己:

allValues :: Value -> [Value]
allValues = universeOf vchildren

此函数提取包含在 a 中的所有文本Value。它使用来自(a 有点像可以传递的“具体化”模式)的_String棱镜:Data.Aeson.LensPrism

allTexts :: Value -> [Text]
allTexts = toListOf (folding allValues . _String)

Control.Lens.Plated还有一些有趣的功能paraOf,比如让你构建“paramorphims”。异形是从叶子开始对树状结构的“受控破坏”,并向上构建结果。例如这个函数

vpara :: (Value -> [r] -> r) -> Value -> r
vpara = paraOf vchildren

将另一个函数作为其第一个参数,该函数接收“当前节点”以及下面节点的中间结果,并为当前节点构建中间结果。

vpara将开始使用叶子中的 JSON 值(这些节点的中间结果列表是简单的[])并继续向上。

一种可能的用途vpara是获取 JSON 中以匹配某些条件的文本结尾的路径列表,如下所示:

type Path = [Value]

pathsThatEndInText :: (Text -> Bool) -> Value -> [Path]
pathsThatEndInText pred = vpara func
  where
    func :: Value -> [[Path]] -> [Path]
    func v@(String txt) _ | pred txt = [[v]]
    func v l@(_:_) = Prelude.map (v:) (Prelude.concat l)
    func _ _ = []

要获得由以下返回的路径之一的可读性描述pathsThatEndInText

import qualified Data.HashMap.Strict as HM
import qualified Data.Vector as V

describePath :: Path -> [String]
describePath (v:vs) = Prelude.zipWith step (v:vs) vs
  where
    step (Object o) next = (unpack . Prelude.head . HM.keys . HM.filter (==next)) o
    step (Array a) next = (show . maybe (error "not found") id) (V.elemIndex next a)
    step _ _ = error "should not happen"

最后,这是一个用于在 ghci 中测试上述函数的 JSON 值示例:

exampleJSON :: Value
exampleJSON = maybe Null id (preview _Value str)
  where
    str = "[{ \"k1\" : \"aaa\" },{ \"k2\" : \"ccc\" }, { \"k3\" : \"ddd\" }]"

这是要点

于 2015-02-20T21:24:10.340 回答