Scala - 使用 Play json 将字符串转换为 Json
Scala - convert String to Json using Play json
我需要帮助使用 playJson
将 json 字符串解析为 scala class
我写了一个格式化程序,但我不知道如何处理嵌套数组。
公文包class是
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"
]
}
}
]
}
}
有什么想法吗?
您可以通过为每个字段单独创建自定义 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")
我根据 oblivion 的评论找到了解决方案,但没有创建多次读取。
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]
我需要帮助使用 playJson
将 json 字符串解析为 scala class我写了一个格式化程序,但我不知道如何处理嵌套数组。
公文包class是
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"
]
}
}
]
}
}
有什么想法吗?
您可以通过为每个字段单独创建自定义 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")
我根据 oblivion 的评论找到了解决方案,但没有创建多次读取。
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]