5

I have a json with complex structure. Something like this:

{
  "a":"aa",
  "b":"bb",
  "c":[
    "aaa",
    "bbb"
  ],
  "d":{
    "e":"ee",
    "f":"ff"
  }
}

And I want to uppercase all string values. The Documentation says:

root.each.string.modify(_.toUpperCase)

But only root values are updated, as expected.

How to make circe-optics traverse all string values recursively?
JSON structure is unknown in advance.

Here is the example on Scastie.


via comments: I am expecting all string values uppercased, not only root values:

{
  "a":"AA",
  "b":"BB",
  "c":[
    "AAA",
    "BBB"
  ],
  "d":{
    "e":"EE",
    "f":"FF"
  }
}
Valy Dia
  • 2,781
  • 2
  • 12
  • 32
Oleg
  • 899
  • 1
  • 8
  • 22

2 Answers2

1

The following might be a new way to do this. Adding it here for completeness.

  import io.circe.Json
  import io.circe.parser.parse
  import io.circe.optics.JsonOptics._
  import monocle.function.Plated

  val json = parse(
    """
      |{
      |  "a":"aa",
      |  "b":"bb",
      |  "c":[
      |    "aaa",
      |    {"k": "asdads"}
      |  ],
      |  "d":{
      |    "e":"ee",
      |    "f":"ff"
      |  }
      |}
      |""".stripMargin).right.get
  val transformed = Plated.transform[Json] { j =>
    j.asString match {
      case Some(s) => Json.fromString(s.toUpperCase)
      case None    => j
    }
  }(json)

  println(transformed.spaces2)

gives

{
  "a" : "AA",
  "b" : "BB",
  "c" : [
    "AAA",
    {
      "k" : "ASDADS"
    }
  ],
  "d" : {
    "e" : "EE",
    "f" : "FF"
  }
}
trudolf
  • 1,809
  • 16
  • 11
0

Here is a partial solution, as in, it is not fully recursive, but it will solve the issue with the json from your example:


val level1UpperCase = root.each.string.modify(s => s.toUpperCase)

val level2UpperCase = root.each.each.string.modify(s => s.toUpperCase)
val uppered = (level1UpperCase andThen level2UpperCase)(json.right.get)

Valy Dia
  • 2,781
  • 2
  • 12
  • 32