使用Scala Play框架解析JSON – 处理可变数组元素?

huangapple go评论57阅读模式
英文:

Parsing JSON with Scala play framework - handling variable array elements?

问题

以下是你提供的内容的翻译部分:

我尝试解析以下形式的搜索结果的 JSON 字符串:

{
  "metadata": [
    "blah",
    "unimportant"
  ],
  "result": [
    {
      "type": "one",
      "title": "this",
      "weird": "attribute unique to this type",
      "other": 7
    },
    {
      "type": "two",
      "title": "that",
      "another_weird": "a different attribute unique to this second type",
      "another": "you get the idea"
    },
    {
      "type": "one",
      "title": "back to this type, which has the same fields as the other element of this type",
      "weird": "yep",
      "other": 8
    }
    // ...
  ]
}

有一个已知的、固定数量的 result 元素类型(由 type 字段给定),每个类型对应一个唯一的模式。对于给定的搜索请求,可以以任何顺序返回每种类型的任意数量(最多达到某个固定总数)。

编写每种类型的 case 类和 Reads 隐式转换是相当容易的,但我的问题是如何处理 result 序列中的变化... 模式匹配似乎是显而易见的选择,但我不确定在 Play 框架中应该在哪里或如何使用。在此先行致谢!

编辑: 根据评论中的建议,我尝试将 result 序列读取为共同基本特质的子类型,但并没有完全成功。以下代码可以编译,但不能正确解析示例 JSON。欢迎任何额外的建议。

sealed trait Parent {def title: String}
case class One(`type`: String, title: String, weird: String, other: Int) extends Parent
case class Two(`type`: String, title: String, another_weird: String, another: String) extends Parent

case class SearchResponse(result: Seq[Parent], metadata: Seq[String])

implicit val oneReader = Json.reads[One]
implicit val twoReader = Json.reads[Two]
implicit val parentReader = Json.reads[Parent]

implicit val searchReader = (
  (__ \ "result").read[Seq[Parent]] and (__ \ "metadata").read[Seq[String]]
)(SearchResponse.apply _)

val searchResult = Json.fromJson[SearchResponse](json)
print(searchResult)

希望这对你有所帮助。

英文:

I'm trying to parse a json string of search results of the following form:

"""
{
  "metadata": [
    "blah",
    "unimportant"
  ],
  "result": [
    {
      "type": "one",
      "title": "this",
      "weird": "attribute unique to this type",
      "other": 7
    },
    {
      "type": "two",
      "title": "that",
      "another_weird": "a different attribute unique to this second type",
      "another": "you get the idea"
    },
    {
      "type": "one",
      "title": "back to this type, which has the same fields as the other element of this type",
      "weird": "yep",
      "other": 8
    }
    ...
  ]
}
"""

There is a known, fixed number of result element types (given by the type field), each of which correspond to a unique schema. For a given search request, there can be any number of each type returned in any order (up to some fixed total).

Writing out the case classes and Reads implicits for each type is easy enough, but my question is around the best way to handle the variability in the result sequence... pattern matching seems the obvious choice, but I'm just not sure where or how with the play framework. Thanks in advance!

EDIT: Per the suggestion in the comments, I gave it a go by attempting to read the result sequence as subtypes of a common base trait, but that didn't quite work. The following compiles, but doesn't parse the example json correctly. Any additional suggestions are welcome.

sealed trait Parent {def title: String}
case class One(`type`: String, title: String, weird: String, other: Int) extends Parent
case class Two(`type`: String, title: String, another_weird: String, another: String) extends Parent

case class SearchResponse(result: Seq[Parent], metadata: Seq[String])

implicit val oneReader = Json.reads[One]
implicit val twoReader = Json.reads[Two]
implicit val parentReader = Json.reads[Parent]

implicit val searchReader = (
  (__ \ "result").read[Seq[Parent]] and (__ \ "metadata").read[Seq[String]]
)(SearchResponse.apply _)

val searchResult = Json.fromJson[SearchResponse](json)
print(searchResult)

答案1

得分: 1

定义隐式 JsonConfiguration

import play.api.libs.json._

sealed trait Parent {
  def title: String
}
case class One(title: String, weird: String, other: Int) extends Parent
case class Two(title: String, another_weird: String, another: String) extends Parent

case class SearchResponse(result: Seq[Parent], metadata: Seq[String])

implicit val cfg = JsonConfiguration(
  discriminator = "type",
  typeNaming = JsonNaming(_.toLowerCase)
)

implicit val oneReader    = Json.reads[One]
implicit val twoReader    = Json.reads[Two]
implicit val parentReader = Json.reads[Parent]
implicit val searchReader = Json.reads[SearchResponse]

val searchResult = Json.fromJson[SearchResponse](json)
println(searchResult)
// JsSuccess(SearchResponse(List(One(this,attribute unique to this type,7), Two(that,a different attribute unique to this second type,you get the idea), One(back to this type, which has the same fields as the other element of this type,yep,8)),List(blah, unimportant)),)

https://www.playframework.com/documentation/2.8.x/ScalaJsonAutomated#Custom-Naming-Strategies

英文:

Define implicit JsonConfiguration

import play.api.libs.json._

sealed trait Parent {
  def title: String
}
case class One(title: String, weird: String, other: Int) extends Parent
case class Two(title: String, another_weird: String, another: String) extends Parent

case class SearchResponse(result: Seq[Parent], metadata: Seq[String])

implicit val cfg = JsonConfiguration(
  discriminator = "type",
  typeNaming = JsonNaming(_.toLowerCase)
)

implicit val oneReader    = Json.reads[One]
implicit val twoReader    = Json.reads[Two]
implicit val parentReader = Json.reads[Parent]
implicit val searchReader = Json.reads[SearchResponse]

val searchResult = Json.fromJson[SearchResponse](json)
println(searchResult)
// JsSuccess(SearchResponse(List(One(this,attribute unique to this type,7), Two(that,a different attribute unique to this second type,you get the idea), One(back to this type, which has the same fields as the other element of this type,yep,8)),List(blah, unimportant)),)

https://www.playframework.com/documentation/2.8.x/ScalaJsonAutomated#Custom-Naming-Strategies

huangapple
  • 本文由 发表于 2023年2月10日 05:39:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/75404683.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定