转换JSON嵌套数组

时间:2015-11-18 13:13:10

标签: json scala playframework

我有JSON结构:

  {
  "date": "2015-01-01",
  "id": 100,
  "movies":[
    {
      "id": 1,
      "length": 131,
      "timestamp": 1447837200
    },
    {
      "id": 2,
      "length": 131,
      "timestamp": 1447840800
    }
]
}

我需要一些验证: - "日期"是一个有效的日期; - " id" - 是目前名单中的一个数字; - "电影" - 是一个对象列表;

转型: - "时间戳" - 将unixtimestamp解析为Date字符串(HH:mm)

我需要把"日期"和" id"从root到每个数组元素

所以,结果对象:

[
    {
      "id": 1,
      "length": 131,
      "timestamp": "09:00",
      "parent_id": 100,
      "date": "2015-01-01"
    },
    {
      "id": 2,
      "length": 131,
      "timestamp": "10:00",
      "parent_id": 100,
      "date": "2015-01-01"
    }
]

我写了一些代码,巫婆转换时间戳,但它看起来很糟糕......

  val inputJson = play.api.libs.json.Json.parse(
    """{
  "date": "2015-01-01",
  "id": 100,
  "movies":[
    {
      "id": 1,
      "length": 131,
      "timestamp": 1447837200
    },
    {
      "id": 2,
      "length": 131,
      "timestamp": 1447840800
    }
]
}"""
  )

  val timestampTransform = (
    ( __ \ "timestamp").json.update(
      __.read[JsNumber].map(
        timestamp => {
          JsString(new DateTime(timestamp.asOpt[Int].getOrElse(0)).toString("HH:mm"))
        } )
    ))

  val reads = ( __ \ 'movies).json.update(
    __.read[JsArray].map(
      movies => {
        val result = movies.as[List[JsObject]].map(
          element => {
            element.transform(timestampTransform).get
          })
        Json.toJson(result)
      }
    )
  )

  println(inputJson.transform(reads))

1 个答案:

答案 0 :(得分:1)

这是另一种可怕的改造方式。

适用于< = play 2.3.x

import play.api.libs.json._
import org.joda.time.DateTime

case class Movie(id: Int, date: String, parent_id: Int, length: Int, timestamp: String)
implicit val mWritess = Json.writes[Movie]
implicit val nreads = new Reads[JsValue] {
  def reads(json: JsValue): JsResult[JsValue] = json match {
    case JsObject(Seq(("date", JsString(date)), ("id", pid: JsNumber), ("movies", JsArray(movies)))) => {
      movies match {
        case s: scala.collection.mutable.ListBuffer[_] => {
          val collectedId: Seq[Movie] = s.collect {
            case JsObject(Seq(("id", mid: JsNumber), ("length", length: JsNumber), ("timestamp", timestamp: JsNumber))) => {
              Movie(mid.asOpt[Int].getOrElse(0), date, pid.asOpt[Int].getOrElse(0), length.asOpt[Int].getOrElse(0), 
              new DateTime(timestamp.asOpt[Int].getOrElse(0)).toString("HH:mm"))
            }
          }
          JsSuccess(Json.toJson(collectedId))
        }
        case _ => JsError(s"Error '$date', $pid, $movies")
      }
    }
    case _ => JsError("Invalid format")
  }
}

println(inputJson.transform(nreads))

适用于播放2.4.x

case class Movie(id: Int, date: String, parent_id: Int, length: Int, timestamp: String)
implicit val mWritess = Json.writes[Movie]
implicit val nreads = new Reads[JsValue] {
  def reads(json: JsValue): JsResult[JsValue] = json match {
    case values: JsObject => {
      values.fields match {
        case Seq(("date", JsString(date)), ("id", pid: JsNumber), ("movies", JsArray(movies))) =>
          movies match {
            case s: scala.collection.mutable.ListBuffer[_] => {
              val collectedId: Seq[Movie] = s.collect {
                case movies: JsObject => {
                  movies.fields match {
                    case Seq(("id", mid: JsNumber), ("length", length: JsNumber), ("timestamp", timestamp: JsNumber)) =>
                      Movie(mid.asOpt[Int].getOrElse(0), date, pid.asOpt[Int].getOrElse(0), length.asOpt[Int].getOrElse(0), 
                      new DateTime(timestamp.asOpt[Int].getOrElse(0)).toString("HH:mm"))
                  }
                }
              }
              JsSuccess(Json.toJson(collectedId))
            }
            case _ => JsError(s"Error '$date', $pid, $movies")
          }
      }
    }
    case _ => JsError("Invalid format")
  }
}

println(inputJson.transform(nreads))
相关问题