簡體   English   中英

使用Argonaut在JSON數組上進行映射

[英]Mapping over a JSON array with Argonaut

我很難通過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)

我猜是這樣的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM