简体   繁体   English

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

[英]Scala Play Json - how to read a single element from a element in an Array?

I am have this json object 我有这个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"
    } ]
  }
}
"""

And with this case class and Reader: 并通过此案例类和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 _)

I try to parse to this model: 我尝试解析为该模型:

Json.parse(jsonObject).validate[Project] match {
  case value: JsSuccess[Project] =>
     println(" >> " + value.get)
  case error: JsError =>
    println(error)
}

The I get this error 我得到这个错误

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

I have no idea how to extract those hrefs from the self array into the Project class to look like this: 我不知道如何将这些href从self数组提取到Project类中,如下所示:

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

I have looked everywhere, on the internet for a simple example that would help me on the right track, but I haven't managed to find anything that helps. 我在互联网上到处都看过一个简单的示例,可以帮助我走上正轨,但我没有找到任何有用的方法。

How can I solve this issue without changing my Project class's structure ? 我如何在不更改Project类结构的情况下解决此问题?

  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))

In your case the JSON object's structure does not map 1:1 onto the case class: Below "self" there is another object (with the "href" property), but this level is missing in your case class. 在您的案例中,JSON对象的结构不会将1:1映射到案例类上:在“自我”下方有另一个对象(具有“ href”属性),但是在案例类中缺少此级别。

So you could modify your JSON data or the case class. 因此,您可以修改JSON数据或案例类。

If you want to preserve both, you can parse into a "parse only" case class, and convert this one into the "target" case class after parsing: 如果要保留两者,则可以解析为“仅解析”案例类,并在解析后将其转换为“目标”案例类:

  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
  }

Anyway, looking at your "clone" property in your JSON object, it seems that you need that additional class Url anyway, as that object contains more than one property. 无论如何,查看JSON对象中的“ clone”属性,似乎仍然需要该附加类Url ,因为该对象包含多个属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM