Haskell 提取Aeson对象内的嵌套属性
如何使用Data.Aeson获取嵌套属性 例如,当使用如下值解码任意JSON字符串时:Haskell 提取Aeson对象内的嵌套属性,haskell,aeson,Haskell,Aeson,如何使用Data.Aeson获取嵌套属性 例如,当使用如下值解码任意JSON字符串时: decode "{\"foo\":{\"bar0\":\"foobar0\", \"bar1\":\"foobar1\"}}" :: Maybe Value 我的结论是: Just (Object (fromList [("foo",Object (fromList [("bar1",String "foobar1"),("bar0",String "foobar0")]
decode "{\"foo\":{\"bar0\":\"foobar0\",
\"bar1\":\"foobar1\"}}" :: Maybe Value
我的结论是:
Just (Object (fromList [("foo",Object (fromList [("bar1",String "foobar1"),("bar0",String "foobar0")]))]))
现在,我如何编写一个函数[String]->Object->Maybe Value来提取通过提供的属性列表得到的值(如果有的话)
此函数的使用方式如下:
extractProperty ["foo", "bar0"] (Object (fromList [("foo",Object (fromList [("bar1",String "foobar1"),("bar0",String "foobar0")]))]))
==> Just (String "foobar0")
extractProperty ["foo", "bar0", "baz"] (Object (fromList [("foo",Object (fromList [("bar1",String "foobar1"),("bar0",String "foobar0")]))]))
==> Nothing
以下解决方案使用了lens和lens aeson软件包:
{-# LANGUAGE FlexibleInstances #-}
import Control.Lens (view,pre,ix) -- from lens
import Control.Lens.Reified (ReifiedTraversal(..))
import Data.Aeson -- from aeson
import Data.Aeson.Lens (_Object) -- from lens-aeson
import Data.Text -- form text
instance Monoid (ReifiedTraversal s s s s) where
mempty = Traversal id
mappend (Traversal t1) (Traversal t2) = Traversal (t1 . t2)
extractProperty :: [Text] -> Object -> Maybe Value
extractProperty keys o =
view (pre telescope) (Object o)
where
telescope = runTraversal $ foldMap (\k -> Traversal $ _Object . ix k) keys
ReifiedTraversal只是一个围绕遍历的新类型,我们在它上面定义了一个Monoid实例,以允许轻松组合以相同类型开始和结束的遍历,类似于Monoid的工作方式
在我们的例子中,遍历对象。IXK从一个值到另一个值。来自Control.Lens.At和对象属性映射上的索引
我们提取组合遍历的第一个结果(如果它与函数一起存在)
编辑:@cchalmers在他的评论中提到,不需要声明孤立实例,只需使用Endo就可以了。此外,键k与_对象相同。IXK
以下是extractProperty的一个版本,它不使用lens,而是依赖于使用foldr组成kleisli箭头值->可能值的列表:
在这种情况下,镜头可能有点过火了。另一种方法,使用一元绑定:
import Data.Text (Text)
import qualified Data.HashMap.Strict as HM
extractProperty :: [Text] -> Value -> Maybe Value
extractProperty [] v = Just v
extractProperty (k:ks) (Object o) = HM.lookup k o >>= prop ks
extractProperty _ _ = Nothing
为什么不直接使用Endo而不是编写一个误导性的孤儿?也反对。ix k=键i。这里有一个更简洁的版本extract ks=预览alaf Endo foldMap key ks。物体。这很优雅,但可能是因为我还没有学过镜头,所以看起来有些过分了。有没有一个更简单、可能是递归的解决方案?@cchalmers你能在一个新的答案中扩展你的建议吗?@cchalmers我有一个错误的印象,即Endo不能很好地处理遍历/镜头。
import Data.Text (Text)
import qualified Data.HashMap.Strict as HM
extractProperty :: [Text] -> Value -> Maybe Value
extractProperty [] v = Just v
extractProperty (k:ks) (Object o) = HM.lookup k o >>= prop ks
extractProperty _ _ = Nothing