jsonscalajson4s

How to remove key but keep childs


I'm new to Scala and I'm trying to process json document. I'm using scala 2.13.3 with the following librairies :

libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.0" % "test"
libraryDependencies += "org.json4s" %% "json4s-native" % "3.6.9"

The problem is that I can't find a way to remove a key and still keep his children as follows:

Here's the json document to begin with:

{
  "Key": {
    "opt": {
      "attribute1": 0,
      "attribute2": 1,
      "attribute3": 2
    },
    "args": {
      "arg1": 0,
      "arg2": 1,
      "arg3": 2
    }
  }
}

I would like to remove the "Key" to keep only his children "opt" and "args" so that I get the Json document below :

{
  "opt": {
    "attribute1": 0,
    "attribute2": 1,
    "attribute3": 2
  },
  "args": {
    "arg1": 0,
    "arg2": 1,
    "arg3": 2
  }
}

My code

I use the Json4s library to manipulate documents, there is a transformField operator that allows to perform operations on fields (key, value) => (key, value). So I tried to define an empty key "" but it doesn't answer my need. I also tried to return only the associated value but the partial function doesn't allow it.

Here is my scala code :

val json: JObject =
  "Key" -> (
    "opt" -> (
      ("attribute1" -> 0) ~
        ("attribute2" -> 1) ~
        ("attribute3" -> 2)
      ) ~
      ("args" -> (
        ("arg1", 0) ~
          ("arg2", 1) ~
          ("arg3", 2)
        )))

val res = json transformField {
  case JField("Key", attr) => attr
}

println(pretty(render(res)))

unfortunatly I can't just use transformField to transform ("Key", attr) into attr.


Is there an easy way to remove the "Key" key from my Json while keeping its children "opt" and "args"?


Solution

  • It is usually better to convert JSON to Scala objects, manipulate the Scala objects, and then convert back to JSON.

    This is what it might look like using jackson:

    import org.json4s.{DefaultFormats, Extraction}
    import org.json4s.jackson.{JsonMethods, Serialization}
    
    val jsonIn = """
      {
        "Key": {
          "opt": {
            "attribute1": 0,
            "attribute2": 1,
            "attribute3": 2
          },
          "args": {
            "arg1": 0,
            "arg2": 1,
           "arg3": 2
         }
       }
     }
    """
    
    case class Opt(attribute1: Int, attribute2: Int, attribute3: Int)
    case class Args(arg1: Int, arg2: Int, arg3: Int)
    case class Key(opt: Opt, args: Args)
    case class DataIn(Key: Key)
    
    implicit val formats = DefaultFormats
    
    val dataIn: DataIn = Extraction.extract[DataIn](JsonMethods.parse(jsonIn))
    
    val jsonOut: String = Serialization.write(dataIn.Key)
    

    In this case the Scala processing is just extracting the Key field from the DataIn class.

    I am on Scala 2.12 so YMMV.