循环光学递归遍历 JSON

Recursive traverse JSON with circe-optics

我有一个结构复杂的json。像这样:

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

而且我想将所有字符串值大写。 The Documentation 说:

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

但正如预期的那样,只有根值被更新。

如何circe-optics递归遍历所有字符串值?
JSON结构事先未知。

这是 Scastie 上的 example


通过评论: 我希望所有字符串值都大写,而不仅仅是根值:

{
  "a":"AA",
  "b":"BB",
  "c":[
    "AAA",
    "BBB"
  ],
  "d":{
    "e":"EE",
    "f":"FF"
  }
}

这是一个部分解决方案,因为它不是完全递归的,但它会解决您示例中 json 的问题:


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)

以下可能是执行此操作的新方法。为了完整起见,将其添加到此处。

  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)

给予

{
  "a" : "AA",
  "b" : "BB",
  "c" : [
    "AAA",
    {
      "k" : "ASDADS"
    }
  ],
  "d" : {
    "e" : "EE",
    "f" : "FF"
  }
}