[英]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. folding
是lens
创建的功能,而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: 我们可以将
vchildren
与Control.Lens.Plated
的universeOf
函数结合使用,以获取提取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\" }]"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.