簡體   English   中英

在 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 <-符號處的Cannot resolve symbol foreach 如何從JsArray內的每個 JSON 對象中檢索特定字段,如email

使用Play 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方式訪問任何字段。

當然,您可以以相同的方式用case classes替換JsObject s - 如果您在我的回答中需要這個,請告訴我。

但在您的情況下,因為您只需要email所以不需要:

resources.map(_.email) // returns Seq[String]

所以就像@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]
}

您還可以使用寫入和讀取而不是 OFormat,或自定義寫入和讀取,我使用 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
}

兩者都適合我。

resources是一個JsArray ,一種不提供.flatMap的類型,因此不能在<-右側使用以進行理解。

val emailReads: Reads[String] = (JsPath \ "email").reads[String]
val resourcesReads = Reads.seqReads(emailReads)

val r: JsResult[Seq[String]] = resources.validate(resources reads)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM