在Scala Play框架中读取JSON树形结构

6
我是一名有帮助的助手,以下是您需要翻译的内容:

我正在尝试在Play框架2.1.3中处理Ajax POST请求。POST数据是一个JSON对象,并且具有树形结构,如下:

{ id: "a", name: "myname", kids : [{ id: "a1", name : "kid1", kids: []}, {id: "a2", name: "kid2", kids: [{id: "aa1", name :"grandkid", kids: []}]}]

我希望可以任意嵌套“子元素”。我想要的类应该像这样(我意识到递归可能有问题):

case class Person {
  id: String,
  name: String,
  kids: Array[Person]
}

我会考虑以下格式:

我心中所想的格式:

implicit val personFormat:Format[Person] = Json.format[Person]

我在我的格式中写了错误,Play提示类型不匹配:找到的是controllers.Resources.Person,但需要的是Array[controllers.Resources.Person]。

我知道Play有一个树形结构,但我找不到如何将其与JSON reads绑定的示例/文档。

非常感谢任何帮助。

2个回答

10
你需要一个递归的值,类似于:

你需要一个递归val,类似于:

implicit val jsonReads: Reads[Person] = ((__ \ "id").read[String] and (__ \ "name").read[String] and (__ \ "kids").read[Seq[Person]])(apply _)
我已经将集合类型从数组(Array)更改为序列(Seq),因为它更通用,使您能够在不影响下游代码的情况下更改实现。这里使用的语法是在这里记录的。

谢谢Robin,我正在尝试整合你的答案,但是我遇到了一个编译错误:“not found: value apply”。我是否缺少一些基本的东西?另外,在你的答案中,Person类中的“kids”需要是“Seq [Person]”吗?谢谢! - Joost
哦,我猜你没有在伴生对象中声明它。所以只需将 apply 更改为 Person。你可以将其更改为 Array,但我不确定 Play 是否可以自动读取 Array;这就是我建议将 Person 中使用的集合类型从 Array 更改为 Seq 的原因。如果我的表述不够清晰,很抱歉。 - Robin Green

2
我认为唯一可行的方法是在你的Person case class中使用JsArray或Array[String],而不是Array[Person]。JSON Macro Inception只能生成原始类型和列表、映射、数组的读写代码,对于已经存在隐式JSON读写代码的对象。基本上,你不能有一个引用自身的case class。
package models

import play.api.libs.json._

case class Person(
  id   : String,
  name : String,
  kids : JsArray
)

object Person extends ((String,String,JsArray) => Person) {

  implicit val jsonFormat = Json.format[Person]

}

1
这并不是好的设计;那是暴露了线性表示法;如果你决定也接受XML呢? - Robin Green
1
问题是如何读取一个JSON结构,XML无关。 - Jason Pearson
1
我在谈论一个潜在的未来设计决策。但是即使不考虑这一点,您也不应该在案例类中公开线路表示 - 这会强制客户端代码关注反序列化,而这是它不必担心的。 - Robin Green
Jason(和Robin),非常感谢你们在这方面的帮助!两个解决方案都完美地运作,并且帮助我更好地理解Play/Scala。谢谢! - Joost

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接