pixel
pixel

Reputation: 26441

Transform String of json objects into array in Scala

I'm having following String:

[{"name":"Bob","age":"23"},{"name":"Alice","age":"31"},...]

and I would like to transform it into an array:

["Bob", "Alice", ...]

How I can achieve that?

Upvotes: 0

Views: 2268

Answers (2)

Branislav Lazic
Branislav Lazic

Reputation: 14806

That's rather easy. Just convert a JSON array to Scala collection and map names. E.g. using Circe:

import io.circe._
import io.circe.generic.auto._

case class Person(name: String, age: Int)

val peopleAsJson = """[{"name":"Bob","age":"23"},{"name":"Alice","age":"31"}]"""

val personNames = decode[Vector[Person]](peopleAsJson).getOrElse(throw new Exception("Encoding failed")).map(_.name).asJson.noSpaces

Or you can just do it via JavaScript if that's an option.

Upvotes: 1

James Whiteley
James Whiteley

Reputation: 3474

One way would be to use Scala's in-built JSON parser. Something like this would work (though it could probably be refactored):

import scala.util.parsing.json._

JSON.parseFull("""[{"name":"Bob","age":"23"},{"name":"Alice","age":"31"}]""") match {
  // get the head and tail of the List and check the head's type
  case Some((m: Map[_, _]) :: l) =>
      m.keys.headOption match {
        // match type of keys - maybe unnecessary but better safe than sorry
        case Some(_: String) =>
          // add the head back to the tail, get name values
          println((m +: l).asInstanceOf[List[Map[String, Any]]]
            .map(_.getOrElse("name", "")))
        case _ => ()
      }
    case _ => ()
}

In REPL:

scala> import scala.util.parsing.json._
import scala.util.parsing.json._

scala> JSON.parseFull("""[{"name":"Bob","age":"23"},{"name":"Alice","age":"31"}]""") match {
     |   case Some((m: Map[_, _]) :: l) =>
     |       m.keys.headOption match {
     |         case Some(_: String) => println((m +: l).asInstanceOf[List[Map[String, Any]]].map(_.getOrElse("name", "")))
     |         case _ => ()
     |       }
     |     case _ => ()
     | }
List(Bob, Alice)
res0: Any = ()

If you have already validated the structure of the JSON though, you can ignore all of the type validation - this stuff just avoids it freaking out if the types don't match (and is more cumbersome than is ideal due to type erasure).

It would be much easier if you were using Scala Play and case classes (which again can probably be refactored):

import play.api.libs.json.{Json, OFormat}

case class Person(name: String, age: String)
object Person {
  implicit val format: OFormat[Person] = Json.format[Person]
}

Json.parse("""[{"name":"Bob","age":"23"},{"name":"Alice","age":"31"}]""")
  .asOpt[List[Person]] match {
  case Some(people) => println(people.map(_.name)) // List(Bob, Alice)
  case _ => println(Seq())
}

Upvotes: 0

Related Questions