如何使用JsPath遍历JSON对象字段?

时间:2022-04-27 23:12:05

Take into account the following JSON provided by a vendor API:

考虑供应商API提供的以下JSON:

import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._

val json = Json.parse(
  """
    |{
    |  "returns": {
    |    "markets" : {
    |      "ABC" : {
    |        "label": "ABC",
    |        "id":1
    |      },
    |      "DEF" : {
    |        "label": "DEF",
    |        "id":2
    |      }
    |    }
    |  }
    |}
  """.stripMargin)

How to extract a sequence of pairs related to "label" and "id" fields. From this piece of JSON the result I'm expecting is:

如何提取与“label”和“id”字段相关的一系列对。从这块JSON中我得到的结果是:

Seq((1,"ABC"),(2,"DEF"))

I'm failing with constructing a correct JsPath extractor because it expects a single match e.g.

我没有构建一个正确的JsPath提取器,因为它需要一个匹配,例如

val jsonTransformer = (__ \ 'returns \ 'markets).json.pick
json.transform(jsonTransformer)

1 个解决方案

#1


3  

Here's how I'd build this parser out of nice composable pieces. First for a general purpose object-to-array transformer that throws away keys:

这是我如何用漂亮的可组合部分构建这个解析器。首先是一个抛出键的通用对象到数组变换器:

val objToArray: Reads[JsArray] =
  JsPath.json.pickBranch.map(obj => JsArray(obj.fields.map(_._2)))

Now for a Reads that can process market objects:

现在可以处理市场对象的Reads:

val marketReads: Reads[(Int, String)] =
  ((__ \ 'id).read[Int] and (__ \ 'label).read[String]).tupled

And now we tie it all together:

现在我们将它们捆绑在一起:

val pairsReads: Reads[List[(Int, String)]] = 
  (__ \ 'returns \ 'markets).read(objToArray) andThen list(marketReads)

And finally:

scala> json.validate(pairsReads).foreach(println)
List((1,ABC), (2,DEF))

Which is what you want. Note that I've specified the types above for clarity, but that's not necessary here—I'd probably leave them out in real code because the pieces are pretty small and straightforward.

这是你想要的。请注意,为了清楚起见,我已经指定了上面的类型,但这里没有必要 - 我可能会将它们留在实际代码中,因为这些部分非常小而且直截了当。

#1


3  

Here's how I'd build this parser out of nice composable pieces. First for a general purpose object-to-array transformer that throws away keys:

这是我如何用漂亮的可组合部分构建这个解析器。首先是一个抛出键的通用对象到数组变换器:

val objToArray: Reads[JsArray] =
  JsPath.json.pickBranch.map(obj => JsArray(obj.fields.map(_._2)))

Now for a Reads that can process market objects:

现在可以处理市场对象的Reads:

val marketReads: Reads[(Int, String)] =
  ((__ \ 'id).read[Int] and (__ \ 'label).read[String]).tupled

And now we tie it all together:

现在我们将它们捆绑在一起:

val pairsReads: Reads[List[(Int, String)]] = 
  (__ \ 'returns \ 'markets).read(objToArray) andThen list(marketReads)

And finally:

scala> json.validate(pairsReads).foreach(println)
List((1,ABC), (2,DEF))

Which is what you want. Note that I've specified the types above for clarity, but that's not necessary here—I'd probably leave them out in real code because the pieces are pretty small and straightforward.

这是你想要的。请注意,为了清楚起见,我已经指定了上面的类型,但这里没有必要 - 我可能会将它们留在实际代码中,因为这些部分非常小而且直截了当。