首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Data.Aeson.Lens进行转换

用Data.Aeson.Lens进行转换
EN

Stack Overflow用户
提问于 2015-05-05 16:55:50
回答 1查看 867关注 0票数 1

使用aeson-lens,我编写了一个非常接近我想要实现的目标的程序:

代码语言:javascript
复制
{-# LANGUAGE OverloadedStrings #-}

import Network.HTTP.Conduit ( simpleHttp )
import Data.Aeson           ( decode
                            , Value
                            )
import Data.Maybe           ( fromJust )
import Control.Lens         ( (^.) )
import Data.Aeson.Lens      ( key, nth )

main :: IO ()
main = do
  pageContents <- simpleHttp "http://127.0.0.1:28017/baseball/team/"
  let v = decode pageContents :: Maybe Value
  let totalRowsVal = v ^. key "total_rows" :: Maybe Int
      oidVal       = v ^. key "rows" . nth 0 ^. key "_id" ^. key "$oid" :: Maybe String
  print totalRowsVal
  print oidVal
  return ()

JSON的内容是:

代码语言:javascript
复制
{
  "total_rows": 2,
  "rows": [
    {
      "_id": { "$oid": "5548ed2671eab385baadf0a7" },
      "abc": 123
    },
    {
      "_id": { "$oid": "5548ed5171eab385baadf0a8" },
      "def": 456
    }
  ],
  "query": {},
  "offset": 0,
  "millis": 0
}

产出如下:

代码语言:javascript
复制
Just 2
Just "5548ed2671eab385baadf0a7"

我想谈一谈输出是:

代码语言:javascript
复制
Just 2
Just [("abc",123),("def",456)]

换句话说,我想从rows键下的值中提取有用的内容,而不事先知道JSON数组元素中的键是什么。我还希望该程序向用户发出信号,表示query键下的值是一个空JSON对象。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-05-05 18:34:33

首先,使用lens-aeson aeson-lens**.** aeson-lens ,而不是,已经有一段时间没有更新了,我不认为它的所有镜头都是守法的。,因为它们都共享Data.Aeson.Lens,所以必须运行ghc-pkg unregister aeson-lens (如果你使用沙箱的话,也可以使用cabal sandbox hc-pkg unregister aeson-lens )。

您还没有详细描述如何知道“有用的内容”是什么,所以我假设它不是"_id",而是指向一个整数。在aeson-lens中,数组的每个对象都是一个HashMap,所以我们首先对这些对象进行遍历:

代码语言:javascript
复制
rows :: Traversal' Value (HM.HashMap Text Value)
rows = key "rows" . _Array . each . _Object
-- or  key "rows" . values

对于行值,我们可以使用索引遍历,其中索引是TextHashMap。然后,我们可以使用ifiltered通过检查索引不是"_id"来过滤内容。我们还使用_Integer只获取指向Integer的东西。

代码语言:javascript
复制
nonIds :: IndexedTraversal' Text (HM.HashMap Text Value)  Integer
nonIds = itraversed . ifiltered (\i _ -> i /= "_id") . _Integer
-- or    members . ifiltered (\i _ -> i /= "_id") . _Integer

从这里可以很容易地得到你想要的清单:

代码语言:javascript
复制
> v ^@.. rows . nonIds
[("abc",123),("def",456)]

(^@..)返回索引遍历的列表及其索引。

要检查“查询”是一个空对象,可以使用nullOf

代码语言:javascript
复制
emptyQuery = nullOf (key "query" . _Object . each) v

下面是一个有用的示例(我将json文件保存为“json.json”):

代码语言:javascript
复制
{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson
import Data.Aeson.Lens
import qualified Data.ByteString.Lazy as LB
import Control.Lens

main :: IO ()
main = do
  contents <- LB.readFile "json.json"
  let Just v = decode contents :: Maybe Value
  let totalRows  = v ^? key "total_rows" . _Integer
      rows       = key "rows" . values
      nonIds     = members . ifiltered (\i _ -> i /= "_id") . _Integer
      vals       = v ^@.. rows . nonIds
      emptyQuery = nullOf (key "query" . members) v
  print totalRows
  print vals
  print emptyQuery

给出了输出

代码语言:javascript
复制
Just 2
[("abc",123),("def",456)]
True

(您可以在这里等效地使用traversetraversed而不是each,它们都在Vector上遍历;我只是觉得each读起来更好。)

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30058936

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档