Hitesh Vaghani
Hitesh Vaghani

Reputation: 1362

How to parse JsArary in scala?

I have following JSON in JsArray(or String) in Scala.

[
  {
    "row1": [
      {
        "seatId": "R1",
        "seatStatus": "BOOKED",
        "seatIsLadies": false
      },
      {
        "seatId": "R3",
        "seatStatus": "AVAILABLE",
        "seatIsLadies": false
      }
    ]
  },
  {
    "row2": [
      {
        "seatId": "R1",
        "seatStatus": "BOOKED",
        "seatIsLadies": false
      },
      {
        "seatId": "R3",
        "seatStatus": "AVAILABLE",
        "seatIsLadies": false
      }
    ]
  },
  {
    "row3": [
      {
        "seatId": "R1",
        "seatStatus": "BOOKED",
        "seatIsLadies": false
      },
      {
        "seatId": "R3",
        "seatStatus": "AVAILABLE",
        "seatIsLadies": false
      },
      {
        "seatId": "R3",
        "seatStatus": "AVAILABLE",
        "seatIsLadies": false
      }
    ]
  }
]

where row1,row2,row3 can vary according to call, sometimes it can be row1-5 or maybe row1-4. How can I parse this JSON? How can I extract row1, row2 and so on?

Upvotes: 1

Views: 247

Answers (2)

Artavazd Balayan
Artavazd Balayan

Reputation: 2413

You can use recursive path operator \\

import play.api.libs.json._

case class RowValue(seatId: String, seatStatus: String, seatIsLadies: Boolean)
object RowValue {
  implicit val rowFormat: Format[RowValue] = Json.using[Json.WithDefaultValues].format[RowValue]
}
// in json is your json string
val js: JsValue = Json.parse(json)
val rowNames: Seq[String] = Seq[String]("row1", "row2", "row3", "row4", "row5")
rowNames.foreach { r =>
  val rowValues = (js \\ r).map(x => x.asOpt[Seq[RowValue]])
  println(s"$r => $rowValues")
}

Output will be:

row1 => ArrayBuffer(Some(List(RowValue(R1,BOOKED,false), RowValue(R3,AVAILABLE,false))))
row2 => ArrayBuffer(Some(List(RowValue(R1,BOOKED,false), RowValue(R3,AVAILABLE,false))))
row3 => ArrayBuffer(Some(List(RowValue(R1,BOOKED,false), RowValue(R3,AVAILABLE,false), RowValue(R3,AVAILABLE,false))))
row4 => ArrayBuffer()
row5 => ArrayBuffer()

Upvotes: 1

Markus1189
Markus1189

Reputation: 2869

The idea is to parse the array as a Vector[JsObject] and then use whatever the key (row1,row2,row3,...) is as a field in a case class Row and parse the inner array as a Vector of seats.

For the following code, please note that I did no error handling! You don't want to just use the .as method, but instead use for example validate and the same goes for the unsafe .head call when building the Row class. Having said that,

here is an ammonite script that does exactly that:

import $ivy.`com.typesafe.play::play-json:2.6.7`

import play.api.libs.json._

case class Row(name: String, seats: Vector[Seat])

case class Seat(seatId: String, seatStatus: String, seatIsLadies: Boolean)

object Seat {
  implicit def format: Format[Seat] = Json.format[Seat]
}

  val inputJson = """
[
  {
    "row1": [
      {
        "seatId": "R1",
        "seatStatus": "BOOKED",
        "seatIsLadies": false
      },
      {
        "seatId": "R3",
        "seatStatus": "AVAILABLE",
        "seatIsLadies": false
      }
    ]
  },
  {
    "row2": [
      {
        "seatId": "R1",
        "seatStatus": "BOOKED",
        "seatIsLadies": false
      },
      {
        "seatId": "R3",
        "seatStatus": "AVAILABLE",
        "seatIsLadies": false
      }
    ]
  },
  {
    "row3": [
      {
        "seatId": "R1",
        "seatStatus": "BOOKED",
        "seatIsLadies": false
      },
      {
        "seatId": "R3",
        "seatStatus": "AVAILABLE",
        "seatIsLadies": false
      },
      {
        "seatId": "R3",
        "seatStatus": "AVAILABLE",
        "seatIsLadies": false
      }
    ]
  }
]
"""

val json = Json.parse(inputJson)

val rowObjs = json.as[Vector[JsObject]]

val result = rowObjs.map(obj => Row(obj.fields.head._1, obj.fields.head._2.as[Vector[Seat]]))

println(result)

Which results in the output:

Vector(
  Row(row1,Vector(Seat(R1,BOOKED,false), Seat(R3,AVAILABLE,false))), 
  Row(row2,Vector(Seat(R1,BOOKED,false), Seat(R3,AVAILABLE,false))), 
  Row(row3,Vector(Seat(R1,BOOKED,false), Seat(R3,AVAILABLE,false),Seat(R3,AVAILABLE,false)))
)

Upvotes: 3

Related Questions