Scala Play Json - 如何从数组元素中读取单个元素?

3

我可以帮你翻译此JSON对象。

val jsonObject = """
 {
  "name" : "camara",
  "project" : {
    "key" : "DOC",
    "name" : "Dockerfiles"
  },
  "cloneUrl" : "https://server/scm/doc/camara.git",
  "links" : {
    "clone" : [ {
      "href" : "https://server/scm/doc/camara.git",
      "name" : "http"
    }, {
      "href" : "ssh://git@server:7999/doc/camara.git",
      "name" : "ssh"
    } ],
    "self" : [ {
      "href" : "url1"
    },
    {
      "href" : "url2"
    } ]
  }
}
"""

使用这个case class和Reader:

case class Project(name: String, project: String, projectUrl: List[String])

implicit val projectReader: Reads[Project] = (
  (JsPath \ "name").read[String] and
  (JsPath \ "project" \ "name").read[String] and
  (JsPath \ "links" \ "self" \\ "href").read[List[String]])(Project.apply _)

我尝试解析这个模型:
Json.parse(jsonObject).validate[Project] match {
  case value: JsSuccess[Project] =>
     println(" >> " + value.get)
  case error: JsError =>
    println(error)
}

我遇到了这个错误

JsError(List((/links/self//href,List(ValidationError(error.path.result.multiple,WrappedArray())))))

我不知道如何将self数组中的href提取到Project类中,使其像这样:

Project(camara,Dockerfiles,List(url1, url2))

我已经在互联网上搜索了很多地方,希望找到一个简单的例子来帮助我走上正确的轨道,但是我还没有找到任何有用的信息。

我如何在不改变我的项目类结构的情况下解决这个问题?


你愿意改变你的案例类结构还是坚持保持现状?如果你愿意改变,我可以帮忙 :) - LuxuryMode
很明显,使用额外的类可以解决这个问题。但是,由于API的限制而被迫进行重构的想法确实令人不悦。 - Firebird
2个回答

3
  import play.api.libs.json._
  import play.api.libs.functional.syntax._
  val jsonObject = """
  {
    "name" : "camara",
    "project" : {
      "key" : "DOC",
      "name" : "Dockerfiles"
    },
    "cloneUrl" : "https://server/scm/doc/camara.git",
    "links" : {
      "clone" : [ {
        "href" : "https://server/scm/doc/camara.git",
        "name" : "http"
      }, {
        "href" : "ssh://git@server:7999/doc/camara.git",
        "name" : "ssh"
      } ],
      "self" : [ {
        "href" : "url1"
      },
      {
        "href" : "url2"
      } ]
    }
  }
  """
  case class Project(name: String, project: String, projectUrl: List[String])

  def multiUrls[T](implicit rt: Reads[T]) = Reads[List[T]] { js =>
    val l: List[JsValue] = (__ \ "links" \ "self" \\ "href")(js)
    Json.fromJson[List[T]](JsArray(l))
  }

implicit val projectReader: Reads[Project] = (
  (JsPath \ "name").read[String] and
  (JsPath \ "project" \ "name").read[String] and
  multiUrls[String])(Project.apply _)

  Json.parse(jsonObject).validate[Project] match {
    case value: JsSuccess[Project] =>
       " >> " + value.get
    case error: JsError =>
      error.toString
  }
  // >> Project(camara,Dockerfiles,List(url1, url2))

3
在您的情况下,JSON对象的结构与案例类没有1:1的映射:在“self”下面还有另一个对象(带有“href”属性),但是在您的案例类中缺少此级别。
因此,您可以修改JSON数据或案例类。
如果您想保留两者,您可以解析为“仅解析”案例类,并在解析后将其转换为“目标”案例类。
  case class Url(href: String)

  case class ParseProject0(
    name: String,
    project: String,
    projectUrl: List[Url]) {

    def toProject: Project = {
      Project(name, project, projectUrl.map(_.href))
    }
  }

  implicit val urlReader: Reads[Url] = (
    (JsPath \ "href").read[String].map(v => Url(v)))

  implicit val projectReader: Reads[ParseProject] = (
    (JsPath \ "name").read[String] and
      (JsPath \ "project" \ "name").read[String] and
      (JsPath \ "links" \ "self").read[List[Url]])(ParseProject.apply _)

  val parsed = Json.parse(jsonObject)
  val result = parsed.validate[ParseProject] match {
    case value: JsSuccess[ParseProject] =>
      val p = value.get.toProject
      p

    case error: JsError =>
      error
  }

无论如何,查看您的JSON对象中的“clone”属性,似乎您仍需要该额外类Url,因为该对象包含多个属性。


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