1

我需要帮助来使用 playJson 将 json 字符串解析为 scala 类

我写了一个格式化程序,但我不知道如何处理嵌套数组。

文档案例类在哪里

case class Document(content: String, score: Double, size: Int, path:String)

和格式化程序

implicit val similarHashFormatter: Format[SimilarHash] = (
  ((__ \ "hits" \ "hits" \\ "fields")(0) \ "content_hash")(0).format[String] and
  (__ \ "hits"  \ "hits" \\ "_score").format[Double] and
  ((__ \ "hits" \ "hits" \\  "fields")(0) \ "ast_size")(0).format[Int] and
  ((__ \ "hits" \ "hits" \\ "fields")(0) \ "path")(0).format[String]
) (SimilarHash.apply, unlift(SimilarHash.unapply))

这是我的源 json

{
  "hits": {
    "hits": [
      {
        "score": 1.5204661,
        "fields": {
          "size": [
            557645
          ],
          "path": [
            "/user/ubuntu/app
          ],
          "content": [
            "images"
          ]
        }
      },
      {        
        "score": 1.5199462,
        "fields": {
          "size": [
            556835
          ],
          "path": [
            "/user/ubuntu/app
          ],
          "content": [
            "documents"
          ]
        }
      }
    ]
  }
}

任何想法 ?

4

2 回答 2

1

您可以通过为每个字段分别创建自定义来做到这一点,Reads如下所示:

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

  case class Document(content: String, score: Double, size: Int, path:String)

  val jsonString = """{
                         "hits": {
                             "hits": [
                                 {
                                     "score": 1.5204661,
                                     "fields": {
                                         "size": [
                                             557645
                                         ],
                                         "path": [
                                             "/user/ubuntu/app"
                                         ],
                                         "content": [
                                             "images"
                                         ]
                                     }
                                 },
                                 {
                                     "score": 1.5199462,
                                     "fields": {
                                         "size": [
                                             556835
                                         ],
                                         "path": [
                                             "/user/ubuntu/app"
                                         ],
                                         "content": [
                                             "documents"
                                         ]
                                     }
                                 }
                             ]
                         }
                     }"""

  val playJson = Json.parse(jsonString)

  val contentReads = new Reads[String] {
    override def reads(json: JsValue): JsResult[String] = json \ "hits" match {
      case JsDefined(o: JsObject) =>
        o \ "hits" match {
          case JsDefined(arr: JsArray) =>
            arr.value.head \ "fields" match {
              case JsDefined(fieldObj: JsObject) =>
                fieldObj \ "content" match {
                  case JsDefined(contentArr: JsArray) =>
                    JsSuccess(Json.stringify(contentArr.value.head))
                  case _ => JsError( """Can't read hits \ hits \ fields \ content""")
                }
              case _ => JsError( """Can't read hits \ hits \ fields""")
              case _ => JsError( """Can't read hits \ hits""")
            }
          case _ => JsError("Can't read hits")
        }
    }
  }

  val sizeReads = new Reads[Int] {
    override def reads(json: JsValue): JsResult[Int] = json \ "hits" match {
      case JsDefined(o: JsObject) =>
        o \ "hits" match {
          case JsDefined(arr: JsArray) =>
            arr.value.head \ "fields" match {
              case JsDefined(fieldObj: JsObject) =>
                fieldObj \ "size" match {
                  case JsDefined(contentArr: JsArray) =>
                    JsSuccess(Json.stringify(contentArr.value.head).toInt)
                  case _ =>  JsError("""Can't read hits \ hits \ fields \ size""")
                }
              case _ => JsError("""Can't read hits \ hits \ fields""")
            }
          case _ => JsError("""Can't read hits \ hits""")
        }
      case _ => JsError("Can't read hits")
    }
  }

  val scoreReads = new Reads[Double] {
    override def reads(json: JsValue): JsResult[Double] = json \ "hits" match {
      case JsDefined(o: JsObject) =>
        o \ "hits" match {
          case JsDefined(arr: JsArray) =>
            arr.value.head \ "score" match {
              case JsDefined(score: JsValue) =>
                JsSuccess(Json.stringify(score).toDouble)
              case _ =>  JsError("""Can't read hits \ hits \ score""")
            }
          case _ => JsError("""Can't read hits \ hits""")
        }
      case _ => JsError("Can't read hits")
    }
  }

  val pathReads = new Reads[String] {
    override def reads(json: JsValue): JsResult[String] = json \ "hits" match {
      case JsDefined(o: JsObject) =>
        o \ "hits" match {
          case JsDefined(arr: JsArray) =>
            arr.value.head \ "fields" match {
              case JsDefined(fieldObj: JsObject) =>
                fieldObj \ "path" match {
                  case JsDefined(contentArr: JsArray) =>
                    JsSuccess(Json.stringify(contentArr.value.head))
                  case _ =>  JsError("""Can't read hits \ hits \ fields \ path""")
                }
              case _ => JsError("""Can't read hits \ hits \ fields""")
            }
          case _ => JsError("""Can't read hits \ hits""")
        }
      case _ => JsError("Can't read hits")
    }
  }

  implicit val documentReads: Reads[Document] = (
  contentReads and
  scoreReads and
  sizeReads and
  pathReads
  )(Document.apply _)

  val document = playJson.validate[Document].get
//result: Document("images",1.5204661,557645,"/user/ubuntu/app")
于 2017-02-11T08:46:09.823 回答
1

我根据遗忘的评论找到了解决方案,但没有创建多次读取。

  implicit val docReader: Reads[Document] = (
        (__ \ "fields" \ "content")(0).read[String] and
        (__  \ "_score").read[Double] and
        ((__ \  "fields") \ "size")(0).read[Int] and
        ((__ \ "fields") \ "path")(0).read[String]
      ) (Document.apply _)


  implicit val docsReader: Reads[Documents] = (
      (__ \ "hits" \ "max_score").read[Double] and
      (__ \ "hits" \ "hits").read[Seq[Document]]
    ) (Documents.apply _)

……最后

val response = Json.parse(inputStream).asOpt[Documents]
于 2017-02-11T15:26:17.157 回答