【问题标题】:Mapping over a JSON array with Argonaut使用 Argonaut 映射 JSON 数组
【发布时间】:2015-03-21 06:25:08
【问题描述】:

我很难浏览 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)
  ))
))

虽然感觉有点冗长。

【问题讨论】:

    标签: scala scalaz argonaut


    【解决方案1】:

    您可以通过 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】:

      这种案例分类可能不是您想要的方式,但这是我的 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)
      

      我猜是这样的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-12
        • 1970-01-01
        • 2015-10-25
        • 2023-03-23
        • 2015-09-08
        相关资源
        最近更新 更多