在Aeson对象中提取嵌套属性

时间:2015-05-11 06:32:17

标签: haskell aeson

如何使用awk -F', *' 'NR == FNR { lb[++i] = $1; ub[i] = $2; next } { anum = substr($1,3,20)+0; for(k=1; k<=i; k++) if (anum >= lb[k] && anum <= ub[k]) print }' file2 file1 200000000000022805177700000000000000000000922820669 xx 200000000000022805181300000000000000000000922820669 xx 获取嵌套属性?

例如,使用Data.Aeson解码任意JSON字符串时,如下所示:

Value

我最终得到了这个:

decode "{\"foo\":{\"bar0\":\"foobar0\",
                  \"bar1\":\"foobar1\"}}" :: Maybe Value

现在,我如何编写一个函数Just (Object (fromList [("foo",Object (fromList [("bar1",String "foobar1"),("bar0",String "foobar0")]))])) ,它将提取[String] -> Object -> Maybe Value,如果有的话,通过提供的属性列表到达?

这个功能应该像这样使用:

Value

2 个答案:

答案 0 :(得分:0)

以下解决方案使用lenslens-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只是Traversal周围的新类型,我们在其上定义了一个Monoid实例,以便轻松组合以相同类型开头和结尾的遍历(类似于Endo monoid工作)。

在我们的案例中,遍历_Object . ix kValue转到Valueix来自Control.Lens.At,并在Object的属性地图上编制索引。

我们使用pre函数提取组合遍历的第一个结果(如果存在)。

编辑:正如@cchalmers在他的评论中提到的,没有必要声明一个孤儿实例,它只能与Endo一起工作。 key k也与_Object . ix k相同。

以下版本的extractProperty不使用lens,而是依赖于使用Value -> Maybe Value撰写kleisli箭头列表foldr

import qualified Data.HashMap.Strict as HM

extractProperty :: [T.Text] -> Object -> Maybe Value 
extractProperty keys o = telescope keys (Object o)
  where
    telescope = foldr (>=>) return . map maybeKey 
    maybeKey k v = case v of 
        Object o -> HM.lookup k o  
        _ -> Nothing 

在这种情况下,lens可能有点矫枉过正。

答案 1 :(得分:0)

使用monadic bind的另一种方法:

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