在 JsArray 中检索对象内的特定字段
Retrieving a particular field inside objects in JsArray
我的部分 JSON 回复如下所示:
"resources": [{
"password": "",
"metadata": {
"updated_at": "20190806172149Z",
"guid": "e1be511a-eb8e-1038-9547-0fff94eeae4b",
"created_at": "20190405013547Z",
"url": ""
},
"iam": false,
"email": "<some mail id>",
"authentication": {
"method": "internal",
"policy_id": "Default"
}
}, {
"password": "",
"metadata": {
"updated_at": "20190416192020Z",
"guid": "6b47118c-f4c8-1038-8d93-ed6d7155964a",
"created_at": "20190416192020Z",
"url": ""
},
"iam": true,
"email": "<some mail id>",
"authentication": {
"method": "internal",
"policy_id": null
}
},
...
]
我正在使用 Play 框架提供的 Json 帮助程序来解析此 Json,如下所示:
val resources: JsArray = response("resources").as[JsArray]
现在我需要从 resources
JsArray 中的所有这些对象中提取字段 email
。为此,我尝试编写一个 foreach 循环,例如:
for (resource <- resources) {
}
但我在 <-
符号处收到错误 Cannot resolve symbol foreach
。如何从 JsArray
中的每个 JSON 对象中检索特定字段,例如 email
用播放JSON我一直用case classes
。所以你的例子看起来像:
import play.api.libs.json._
case class Resource(password: String, metadata: JsObject, iam: Boolean, email: String, authentication: JsObject)
object Resource {
implicit val jsonFormat: Format[Resource] = Json.format[Resource]
}
val resources: Seq[Resource] = response("resources").validate[Seq[Resource]] match {
case JsSuccess(res, _) => res
case errors => // handle errors , e.g. throw new IllegalArgumentException(..)
}
现在您可以 type-safe
方式访问任何字段。
当然,您可以用相同的方式将 JsObject
替换为 case classes
- 如果您在我的回答中需要这个,请告诉我。
但在你的情况下,你只需要 email
就没有必要了:
resources.map(_.email) // returns Seq[String]
resources
是一个 JsArray
,一种不提供 .flatMap
的类型,因此不能在 for comprehension 中用在 <-
的右边。
val emailReads: Reads[String] = (JsPath \ "email").reads[String]
val resourcesReads = Reads.seqReads(emailReads)
val r: JsResult[Seq[String]] = resources.validate(resources reads)
所以就像@pme 说你应该使用 case 类,它们应该看起来像这样:
import java.util.UUID
import play.api.libs.json._
case class Resource(password:String, metadata: Metadata, iam:Boolean, email:UUID, authentication:Authentication)
object Resource{
implicit val resourcesImplicit: OFormat[Resource] = Json.format[Resource]
}
case class Metadata(updatedAt:String, guid:UUID, createdAt:String, url:String)
object Metadata{
implicit val metadataImplicit: OFormat[Metadata] = Json.format[Metadata]
}
case class Authentication(method:String, policyId: String)
object Authentication{
implicit val authenticationImplicit: OFormat[Authentication] =
Json.format[Authentication]
}
您也可以使用 Writes 和 Reads 而不是 OFormat,或者自定义 Writes 和 Reads,我使用 OFormat 是因为它不那么冗长。
然后当你有你的回复时,你验证它们,你可以按照@pme 所说的方式或我做的方式验证它们:
val response_ = response("resources").validate[Seq[Resource]]
response_.fold(
errors => Future.succeful(BadRequest(JsError.toJson(errors)),
resources => resources.map(_.email))// extracting emails from your objects
???
)
所以这里你在 Json 无效时做一些事情,在 Json 有效时做另一件事,行为与 pme 所做的相同,在我看来只是更优雅一点
假设您的 json 看起来像这样:
val jsonString =
"""
|{
| "resources": [
| {
| "password": "",
| "metadata": {
| "updated_at": "20190806172149Z",
| "guid": "e1be511a-eb8e-1038-9547-0fff94eeae4b",
| "created_at": "20190405013547Z",
| "url": ""
| },
| "iam": false,
| "email": "<some mail id1>",
| "authentication": {
| "method": "internal",
| "policy_id": "Default"
| }
| },
| {
| "password": "",
| "metadata": {
| "updated_at": "20190416192020Z",
| "guid": "6b47118c-f4c8-1038-8d93-ed6d7155964a",
| "created_at": "20190416192020Z",
| "url": ""
| },
| "iam": true,
| "email": "<some mail id2>",
| "authentication": {
| "method": "internal",
| "policy_id": null
| }
| }
| ]
|}
""".stripMargin
你可以做到:
(Json.parse(jsonString) \ "resources").as[JsValue] match{
case js: JsArray => js.value.foreach(x => println((x \ "email").as[String]))
case x => println((x \ "email").as[String])
}
或:
(Json.parse(jsonString) \ "resources").validate[JsArray] match {
case s: JsSuccess[JsArray] => s.get.value.foreach(x => println((x \ "email").as[String]))
case _: JsError => arr().value //or do something else
}
都适合我。
我的部分 JSON 回复如下所示:
"resources": [{
"password": "",
"metadata": {
"updated_at": "20190806172149Z",
"guid": "e1be511a-eb8e-1038-9547-0fff94eeae4b",
"created_at": "20190405013547Z",
"url": ""
},
"iam": false,
"email": "<some mail id>",
"authentication": {
"method": "internal",
"policy_id": "Default"
}
}, {
"password": "",
"metadata": {
"updated_at": "20190416192020Z",
"guid": "6b47118c-f4c8-1038-8d93-ed6d7155964a",
"created_at": "20190416192020Z",
"url": ""
},
"iam": true,
"email": "<some mail id>",
"authentication": {
"method": "internal",
"policy_id": null
}
},
...
]
我正在使用 Play 框架提供的 Json 帮助程序来解析此 Json,如下所示:
val resources: JsArray = response("resources").as[JsArray]
现在我需要从 resources
JsArray 中的所有这些对象中提取字段 email
。为此,我尝试编写一个 foreach 循环,例如:
for (resource <- resources) {
}
但我在 <-
符号处收到错误 Cannot resolve symbol foreach
。如何从 JsArray
email
用播放JSON我一直用case classes
。所以你的例子看起来像:
import play.api.libs.json._
case class Resource(password: String, metadata: JsObject, iam: Boolean, email: String, authentication: JsObject)
object Resource {
implicit val jsonFormat: Format[Resource] = Json.format[Resource]
}
val resources: Seq[Resource] = response("resources").validate[Seq[Resource]] match {
case JsSuccess(res, _) => res
case errors => // handle errors , e.g. throw new IllegalArgumentException(..)
}
现在您可以 type-safe
方式访问任何字段。
当然,您可以用相同的方式将 JsObject
替换为 case classes
- 如果您在我的回答中需要这个,请告诉我。
但在你的情况下,你只需要 email
就没有必要了:
resources.map(_.email) // returns Seq[String]
resources
是一个 JsArray
,一种不提供 .flatMap
的类型,因此不能在 for comprehension 中用在 <-
的右边。
val emailReads: Reads[String] = (JsPath \ "email").reads[String]
val resourcesReads = Reads.seqReads(emailReads)
val r: JsResult[Seq[String]] = resources.validate(resources reads)
所以就像@pme 说你应该使用 case 类,它们应该看起来像这样:
import java.util.UUID
import play.api.libs.json._
case class Resource(password:String, metadata: Metadata, iam:Boolean, email:UUID, authentication:Authentication)
object Resource{
implicit val resourcesImplicit: OFormat[Resource] = Json.format[Resource]
}
case class Metadata(updatedAt:String, guid:UUID, createdAt:String, url:String)
object Metadata{
implicit val metadataImplicit: OFormat[Metadata] = Json.format[Metadata]
}
case class Authentication(method:String, policyId: String)
object Authentication{
implicit val authenticationImplicit: OFormat[Authentication] =
Json.format[Authentication]
}
您也可以使用 Writes 和 Reads 而不是 OFormat,或者自定义 Writes 和 Reads,我使用 OFormat 是因为它不那么冗长。
然后当你有你的回复时,你验证它们,你可以按照@pme 所说的方式或我做的方式验证它们:
val response_ = response("resources").validate[Seq[Resource]]
response_.fold(
errors => Future.succeful(BadRequest(JsError.toJson(errors)),
resources => resources.map(_.email))// extracting emails from your objects
???
)
所以这里你在 Json 无效时做一些事情,在 Json 有效时做另一件事,行为与 pme 所做的相同,在我看来只是更优雅一点
假设您的 json 看起来像这样:
val jsonString =
"""
|{
| "resources": [
| {
| "password": "",
| "metadata": {
| "updated_at": "20190806172149Z",
| "guid": "e1be511a-eb8e-1038-9547-0fff94eeae4b",
| "created_at": "20190405013547Z",
| "url": ""
| },
| "iam": false,
| "email": "<some mail id1>",
| "authentication": {
| "method": "internal",
| "policy_id": "Default"
| }
| },
| {
| "password": "",
| "metadata": {
| "updated_at": "20190416192020Z",
| "guid": "6b47118c-f4c8-1038-8d93-ed6d7155964a",
| "created_at": "20190416192020Z",
| "url": ""
| },
| "iam": true,
| "email": "<some mail id2>",
| "authentication": {
| "method": "internal",
| "policy_id": null
| }
| }
| ]
|}
""".stripMargin
你可以做到:
(Json.parse(jsonString) \ "resources").as[JsValue] match{
case js: JsArray => js.value.foreach(x => println((x \ "email").as[String]))
case x => println((x \ "email").as[String])
}
或:
(Json.parse(jsonString) \ "resources").validate[JsArray] match {
case s: JsSuccess[JsArray] => s.get.value.foreach(x => println((x \ "email").as[String]))
case _: JsError => arr().value //or do something else
}
都适合我。