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



我很难浏览Argonaut文档,所以我想我只需要一个简单的例子。

val input = """{"a":[{"b":4},{"b":5}]}"""
val output = ??? // desired value: List(4, 5)

我可以把光标放在数组上:

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})))))

但后来呢?我走对了吗?我应该使用游标吗?

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

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

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

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])))

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

Parse.parse(input).map(_.as(
  DecodeJson(_.downField("a").as(
    IListDecodeJson(DecodeJson(_.downField("b").as[Int])).map(_.toList)
  ))
))

不过感觉有点冗长。

在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

然后:

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

运算符一开始看起来很糟糕,但你会习惯它们,组成的部分读起来很自然。当然,由于这是一个镜头,除了getAll,你还可以使用各种操作。

这个案例分类可能不是你想要的方式,但这是我的2美分。

case class B(b: Int)
object B {
  implicit def BCodecJson: CodecJson[B] =
  casecodec1(B.apply, B.unapply)("b")
}
val jsonString = """{"a":[{"b":4},{"b":5}]}"""
val vals: List[Int] = Parse.parseOption(jsonString).map { json: Json =>
    (json -|| List("a")).flatMap(_.as[List[B]].value).getOrElse(Nil).map(_.b)
  }.getOrElse(Nil)

我想就是这样。

相关内容

  • 没有找到相关文章

最新更新