Search code examples
scalalensescirce

How to parse nested Json Arrays with Circe Optics


I read the example given by the Circe docs using Circe Optics. The example in the docs is pretty straight forward because the path to the node is pretty easy to find.

In my case the json looks like

import io.circe._, io.circe.parser._

val json = """[["a",{"entity":["foo"]}],["b",{"entity":["bar"]}]]"""

This is a valid json and I can parse is using parse(json)

But how do I write a lens so that I extract all "foo", "bar".


Solution

  • If you want the fancy JsonPath style, you can use each to select every matching member of a JSON array, so your path could look like this:

    import io.circe.optics.JsonPath
    
    val entities = JsonPath.root.each.each.entity.each.string
    

    And then supposing you have the following Json value:

    import io.circe.jawn.parse
    
    val Right(json) = parse("""[["a",{"entity":["foo"]}],["b",{"entity":["bar"]}]]""")
    

    You could use the Traversal path like this:

    scala> entities.getAll(json)
    res0: List[String] = List(foo, bar)
    
    scala> entities.modify(_ * 2)(json).noSpaces
    res1: String = [["a",{"entity":["foofoo"]}],["b",{"entity":["barbar"]}]]
    
    scala> entities.set("___")(json).noSpaces
    res2: String = [["a",{"entity":["___"]}],["b",{"entity":["___"]}]]
    

    You could also construct the path explicitly, but it'd involve a lot more code.