title: Arbitrary nested JSON to Map in Scala using json4s
body: <p>I am using json4s in Scala. Now, given the following JSON:</p>
  
  <pre><code>{
   'k1': [
    {"a" : "hello1", "b": "city1" },
    {"a" : "hello2", "b": "city2" },
    {"a" : "hello2", "b": "city2" } 
   ],
   'k2': [
    {"a" : "hello1", "b": "city1" },
    {"a" : "hello2", "b": "city2" },
    {"a" : "hello2", "b": "city2" } 
   ]
  }
  </code></pre>
  
  <p>What is the shortest way to transform it into a one-level Map in Scala:</p>
  
  <pre><code>Map(
  "k1.$[0].a" =&gt; "hello1",
  "k1.$[0].b" =&gt; "city1",
  "k1.$[1].a" =&gt; "hello2",
  "k1.$[1].b" =&gt; "city2",
  "k1.$[2].a" =&gt; "hello2",
  "k1.$[2].b" =&gt; "city2",
  "k2.$[0].a" =&gt; "hello1",
  "k2.$[0].b" =&gt; "city1",
  "k2.$[1].a" =&gt; "hello2",
  "k2.$[1].b" =&gt; "city2",
  "k2.$[2].a" =&gt; "hello2",
  "k2.$[2].b" =&gt; "city2"
  )
  </code></pre>
  
  <p>Note that, the top-level JSON will always be an Object, and not an Array i.e. <code>{}</code> and not <code>[]</code>. Also it could be nested deep with no limits known in advance.</p>
  
  <p><strong>EDIT1</strong></p>
  
  <p>Alright this is what I am currently doing:</p>
  
  <pre><code>import org.json4s._
  import org.json4s.native.JsonMethods._
  
  object Experiments {
    def toMap(json: JValue, prefix: String = ""): Map[String, Any] = {
      json match {
        case obj: JObject =&gt;
          obj.values flatMap {
            case (k, v) =&gt;
              toMap(v.asInstanceOf[JValue], prefix + s".$k")
          }
        case arr: JArray =&gt;
          val returnValues = arr.values.zipWithIndex flatMap {
            case (v, index) =&gt;
              toMap(v.asInstanceOf[JValue], prefix + s".$$[$index]")
          }
          returnValues.toMap
        case value: JBool =&gt;
          Map(prefix -&gt; value)
        case value: JDecimal =&gt;
          Map(prefix -&gt; value)
        case value: JDouble =&gt;
          Map(prefix -&gt; value)
        case value: JInt =&gt;
          Map(prefix -&gt; value)
        case value: JString =&gt;
          Map(prefix -&gt; value)
        case JNothing | JNull =&gt;
          Map(prefix -&gt; JNull)
      }
    }
  
    def main(args: Array[String]) {
      val json2 = parse( """ {"a": {"b": "c"}} """)
      print(toMap(json2))
    }
  }
  </code></pre>
  
  <p>It doesn't work and I am getting this error:</p>
  
  <pre><code>Exception in thread "main" java.lang.ClassCastException: scala.collection.immutable.Map$Map1 cannot be cast to org.json4s.JsonAST$JValue
      at Experiments$$anonfun$toMap$1.apply(Experiments.scala:10)
      at Experiments$$anonfun$toMap$1.apply(Experiments.scala:8)
      at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:252)
      at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:252)
      at scala.collection.immutable.Map$Map1.foreach(Map.scala:116)
      at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:252)
      at scala.collection.AbstractTraversable.flatMap(Traversable.scala:104)
      at Experiments$.toMap(Experiments.scala:8)
      at Experiments$.main(Experiments.scala:35)
      at Experiments.main(Experiments.scala)
  </code></pre>
  
  <p><strong>EDIT2</strong></p>
  
  <p>Following code works for me:</p>
  
  <pre><code>import org.json4s._
  import org.json4s.native.JsonMethods._
  
  object Experiments {
  
    def toMap(v: Any, prefix: String = "", separator: String = "/"): Map[String, Any] = {
      v match {
        case m: Map[_, _] =&gt;
          m.flatMap { case (k, v) =&gt;
            toMap(v, prefix + s"$separator$k")
          }
        case list: List[_] =&gt;
          val returnValues = list.zipWithIndex flatMap {
            case (v, index) =&gt;
              toMap(v, prefix + s"$separator$$[$index]")
          }
          returnValues.toMap
        case _ =&gt;
          Map(prefix -&gt; v)
      }
    }
  
    def main(args: Array[String]) {
      val s1 = """ {"a": {"b": "c"}} """
      val s2 =
        """
      {
        "k1": [ {"a" : "hello1", "b": "city1" }, {"a" : "hello2", "b": "city2" }, {"a" : "hello2", "b": "city2" } ] ,
        "k2": [ {"a" : "hello1", "b": "city1" }, {"a" : "hello2", "b": "city2" }, {"a" : "hello2", "b": "city2" } ]
      }
        """
  
      for (s &lt;- List(s1, s2)) {
        println(s"JSON string: $s")
        val json2 = parse(s)
        val flatm = toMap(json2.values)
        flatm foreach println
        println()
      }
    }
  }
  </code></pre>
  
  <p><strong>OUTPUT2</strong></p>
  
  <pre><code>JSON string:  {"a": {"b": "c"}} 
  (/a/b,c)
  
  JSON string: 
      {
        "k1": [ {"a" : "hello1", "b": "city1" }, {"a" : "hello2", "b": "city2" }, {"a" : "hello2", "b": "city2" } ] ,
        "k2": [ {"a" : "hello1", "b": "city1" }, {"a" : "hello2", "b": "city2" }, {"a" : "hello2", "b": "city2" } ]
      }
  
  (/k1/$[2]/a,hello2)
  (/k2/$[0]/a,hello1)
  (/k1/$[2]/b,city2)
  (/k1/$[1]/a,hello2)
  (/k2/$[1]/a,hello2)
  (/k1/$[1]/b,city2)
  (/k2/$[2]/a,hello2)
  (/k2/$[0]/b,city1)
  (/k1/$[0]/a,hello1)
  (/k2/$[1]/b,city2)
  (/k2/$[2]/b,city2)
  (/k1/$[0]/b,city1)
  </code></pre>