简体   繁体   English

如何检查解析后的Aeson价值?

[英]How to inspect parsed Aeson Value?

How can I browse large Aeson Values ? 如何浏览大Aeson Values I know there should be a string I'm interested in nested somewhere in the structure. 我知道应该有一个我感兴趣的字符串嵌套在结构中的某个位置。 How can I find it? 我如何找到它?

So far I only know how to query constructor and found out it's an Array. 到目前为止,我只知道如何查询构造函数,发现它是一个数组。 How can I dig deeper than that? 我怎么能比这更深入?

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

The lens package has useful functions for inspecting tree-like structures like JSON Value s. lens软件包具有有用的功能,可用于检查类似JSON Value的树状结构。 There's also the lens-aeson package with extra JSON-specific functions. 还有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)

We can begin by defining a lens Fold that extracts the immediate child Values of a given JSON Value : 我们可以从定义镜头Fold开始,该镜头Fold提取给定JSON Value的直接子Values

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

folding is a function from lens that creates a Fold out a function that returns a list. foldinglens创建的功能,而Fold是返回列表的功能。 A list of Value s, in our case. 在我们的例子中,是Value的列表。

We can combine vchildren with the universeOf function from Control.Lens.Plated to get a function that extracts all the transitive descendants of a Value , including itself: 我们可以将vchildrenControl.Lens.PlateduniverseOf函数结合使用,以获取提取Value 所有传递后代(包括其自身)的函数:

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

And this function extracts all the texts contained in a Value . 并且此函数提取Value中包含的所有文本。 It uses the _String prism from Data.Aeson.Lens (a Prism is a bit like a "reified" pattern that can be passed around): 它使用_String从棱镜Data.Aeson.Lens (一个Prism是有点像可以被传递了“具体化”模式):

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

Control.Lens.Plated also has interesting functions like paraOf , that let you build "paramorphims". Control.Lens.Plated还具有诸如paraOf类的有趣功能,可用于构建“ paramorphims”。 A paramorphism is a "controlled destruction" of a tree-like structure starting from the leaves, and building the results upward. 亚同态是从叶子开始的树状结构的“受控破坏”,并向上构建结果。 For example, this function 例如这个功能

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

takes as its first parameter another function that receives the "current node" along with the intermediate results for the nodes below, and builds the intermediate result for the current node. 将另一个函数作为其第一个参数,该函数接收“当前节点”以及下面节点的中间结果,并构建当前节点的中间结果。

vpara will start consuming the JSON value from the leaves (the intermediate result list for those nodes is simply [] ) and proceeds upwards. vpara将开始从叶子中使用JSON值(这些节点的中间结果列表只是[] )并向上进行。

One possible use of vpara is obtaining the list of paths in the JSON that end in a text that matches some condition, like this: 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 _ _ = []

To obtain a somewhat readable description of one of the paths returned by pathsThatEndInText : 为了获得由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"

Finally, here's an example JSON value for testing the above functions in ghci: 最后,这是一个示例JSON值,用于在ghci中测试上述功能:

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

And here's the gist . 这就是要点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM