Search code examples
jsonscalarecursionscala-cats

Replacing all JSON String values recursively with Circe


Using the CIRCE library & Cats, it would be incredibly useful to be able to transform all the string values of an arbitrary Json object such as

{
  "topLevelStr" : "topLevelVal", 
  "topLevelInt" : 123, 
  "nested" : { "nestedStr" : "nestedVal" },
  "array" : [
    { "insideArrayStr" : "insideArrayVal1", "insideArrayInt" : 123},
    { "insideArrayStr" : "insideArrayVal2", "insideArrayInt" : 123}
   ]
}

Is it possble to transform all string values (topLevelVal, nestedVal, insideArrayVal1, insideArrayVal2) to upper case (or any arbitrary string transformation for that matter)?


Solution

  • You can write recursive function by yourself. It should be something like that:

    import io.circe.{Json, JsonObject}
    import io.circe.parser._
    
    
    def transform(js: Json, f: String => String): Json = js
      .mapString(f)
      .mapArray(_.map(transform(_, f)))
      .mapObject(obj => {
        val updatedObj = obj.toMap.map {
          case (k, v) => f(k) -> transform(v, f)
        }
        JsonObject.apply(updatedObj.toSeq: _*)
      })
    
    val jsonString =
      """
        |{
        |"topLevelStr" : "topLevelVal",
        |"topLevelInt" : 123, 
        | "nested" : { "nestedStr" : "nestedVal" },
        | "array" : [
        |   {
        |      "insideArrayStr" : "insideArrayVal1",
        |      "insideArrayInt" : 123
        |   }
        |  ]
        |}
      """.stripMargin
    
    val json: Json = parse(jsonString).right.get
    println(transform(json, s => s.toUpperCase))