使用Argonaut在JSON数组上进行映射

Chr*_*tin 4 scala scalaz argonaut

我很难通过Argonaut文档,所以我想我只想问一个简单的例子.

val input = """{"a":[{"b":4},{"b":5}]}"""

val output = ??? // desired value: List(4, 5)
Run Code Online (Sandbox Code Playgroud)

我可以将光标放到数组中:

Parse.parse(input).map((jObjectPL >=> jsonObjectPL("a") >=> jArrayPL)(_))
// scalaz.\/[String,Option[scalaz.IndexedStore[argonaut.Argonaut.JsonArray,
//  argonaut.Argonaut.JsonArray,argonaut.Json]]] =
// \/-(Some(IndexedStoreT((<function1>,List({"b":4}, {"b":5})))))
Run Code Online (Sandbox Code Playgroud)

但那又怎样?我是在正确的轨道上吗?我甚至应该使用游标吗?

编辑 - 我想这是一些进展.我为列表写了一个解码器:

Parse.parse("""[{"b": 4}, {"b": 5}]""")
  .map(_.as(IListDecodeJson(DecodeJson(_.downField("b").as[Int]))))
// scalaz.\/[String,argonaut.DecodeResult[scalaz.IList[Int]]] =
// \/-(DecodeResult(\/-([4,5])))
Run Code Online (Sandbox Code Playgroud)

编辑 - 慢慢开始把它放在一起......

Parse.parse(input).map(_.as[HCursor].flatMap(_.downField("a").as(
  IListDecodeJson(DecodeJson(_.downField("b").as[Int])))))
// scalaz.\/[String,argonaut.DecodeResult[scalaz.IList[Int]]] =
// \/-(DecodeResult(\/-([4,5])))
Run Code Online (Sandbox Code Playgroud)

编辑 - 所以我想到目前为止我的最佳解决方案是:

Parse.parse(input).map(_.as(
  DecodeJson(_.downField("a").as(
    IListDecodeJson(DecodeJson(_.downField("b").as[Int])).map(_.toList)
  ))
))
Run Code Online (Sandbox Code Playgroud)

但是感觉有点冗长.

Tra*_*own 9

你可以很好地利用Argonaut中新的Monocle支持(我在这里使用Argonaut master,因为6.1里程碑仍在Monocle 0.5上):

import argonaut._, Argonaut._
import scalaz._, Scalaz._
import monocle._, Monocle._

val lens =
  Parse.parseOptional ^<-? 
  jObjectPrism        ^|-?
  index("a")          ^<-?
  jArrayPrism         ^|->>
  each                ^<-?
  jObjectPrism        ^|-?
  index("b")          ^<-?
  jIntPrism
Run Code Online (Sandbox Code Playgroud)

然后:

scala> lens.getAll("""{"a":[{"b":4},{"b":5}]}""")
res0: scalaz.IList[Int] = [4,5]
Run Code Online (Sandbox Code Playgroud)

操作员起初看起来很可怕,但你已经习惯了它们,而且组合的部分很自然地阅读.当然,由于这是一个镜头,除此之外还有各种各样的操作getAll.