簡體   English   中英

如何在 Scala Play 框架 2 中將 JSON 字段轉換為 Seq?

[英]How do I transform a JSON fields into a Seq in Scala Play framework 2?

我有一些來自外部 API 的 JSON,我無法控制。 部分 JSON 格式如下:

{
  "room_0": {
    "area_sq_ft": 151.2
  },
  "room_1": {
    "area_sq_ft": 200.0
  }
}

他們沒有像他們應該使用的那樣使用數組,而是使用 room_n 作為 n 個元素的鍵。 我不想使用 room_0、room_1、room_2 等創建案例類,而是想將其轉換為 Seq[Room],其中這是我的 Room 案例類:

case class Room(area: Double)

我正在使用play.api.libs.json Reads 將 JSON 的其他部分轉換為 case 類,並且更喜歡使用 Reads 進行此轉換。 我怎么能做到這一點?

這是我嘗試過的。

val sqFtReads = (__ \ "size_sq_ft").read[Double]
val roomReads = (__ \ "size_sq_ft").read[Seq[Room]](sqFtReads).map(Room) 
cmd19.sc:1: overloaded method value read with alternatives:
  (t: Seq[$sess.cmd17.Room])play.api.libs.json.Reads[Seq[$sess.cmd17.Room]] <and>
  (implicit r: play.api.libs.json.Reads[Seq[$sess.cmd17.Room]])play.api.libs.json.Reads[Seq[$sess.cmd17.Room]]
 cannot be applied to (play.api.libs.json.Reads[Double])
val roomReads = (__ \ "size_sq_ft").read[Seq[Room]](sqFtReads).map(Room)

一個棘手的小挑戰,但完全可以通過Reads實現。

首先, Reads[Room] - 即單個Room實例的轉換器:

val roomReads = new Reads[Room] {
  override def reads(json: JsValue): JsResult[Room] = {
    (json \ "area_sq_ft").validate[Double].map(Room(_))
  }
}

非常簡單; 我們查看 JSON 並嘗試找到一個名為area_sq_ft的頂級字段,該字段驗證為Double 如果一切順利,我們會根據需要返回填充的Room實例。

接下來,您的上游對象的轉換器,以良好的Postel 定律方式,您正在為您自己的消費者進行清理。

val strangeObjectReads = new Reads[Seq[Room]] {
  override def reads(json: JsValue): JsResult[Seq[Room]] = {

    json.validate[JsObject].map { jso =>

      val roomsSortedNumerically = jso.fields.sortBy { case (name, contents) =>
        val numericPartOfRoomName = name.dropWhile(!_.isDigit)
        numericPartOfRoomName.toInt
      }

      roomsSortedNumerically.map { case (name, contents) =>
        contents.as[Room](roomReads)
      }

    }
  }
}

這里的關鍵是整個json.validate[JsObject] 通過map ping,我們得到了我們需要包裝整個事物的JsResult ,此外,我們可以訪問 JSON 對象中的fields ,該對象定義為Seq[(String, JsValue)]

為了確保我們在輸出序列中以正確的順序放置字段,我們進行了一些字符串操作,獲取room_1字符串的數字部分,並將其用作sortBy條件。 我在這里有點天真,並假設您的上游服務器不會做任何諸如跳過房間號碼之類的令人討厭的事情!

一旦您按數字對房間進行了排序,我們就可以對它們進行map ,使用我們的roomReads轉換器轉換每個roomReads

您可能已經注意到,我的自定義Reads實現絕對不是單行的。 這來自處理奇怪的上游 JSON 格式的痛苦經驗。 有點冗長,當上游服務器突然更改其 JSON 格式時,使用更多變量並稍微分解一下會帶來很大的回報!

暫無
暫無

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

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