0
votes

since a while I am fooling around with the following problem.

I try to recursivly transform through a tree-like json structure.

{
    "id": 21,
    "title": "Title1",
    "children": [
        {
            "id": 22,
            "title": "Title1.1",
            "children": [
                {
                    "id": 33,
                    "title": "Title1.1.1",
                    "children": [
                        {
                            "id": 41,
                            "title": "Title1.1.1.1",
                            "children": [
                                {
                                    "id": 42,
                                    "title": "Title1.1.1.1.1",
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}

So far I have :

  val idChanger:Reads[JsObject] = (__ \ 'id).json.update(of[JsNumber].map{case JsNumber(nb) => JsNumber(nb * 100)})

  val childPicker:Reads[JsValue] = (__ \ 'children).json.pick[JsArray].map{
    case JsArray(arr) => JsArray(arr.map(o => {
      o.transform(idChanger) match {
        case JsSuccess(value, jsPath) =>
          println(s"Success:$value")
          value
        case JsError(errors) =>
          println(s"Error:$errors"); JsNull
      }
    }))
  }

val jsvalue: JsValue = ...
jsvalue.transform(childPicker)
...

This works only on the first level and changes the id '21' accordingly, but not the rest so far.

I tried many different ways to do the rest of the children recursivly too, but no success so far.

Any help on this one would be appreciated.

Cheers, Rob.

1
Hi, it does not fail, but I just do not get the recursion working (In the code above there is no recursion, but this is the base I used to get the recursion somehow in). The solution might be completely different and the approach above is completely wrong, but I have no other idea. So far. - Rob

1 Answers

1
votes

Just add the recursive call inside your Reads and make sure to handle JsArray as well as JsObject. Here is a simple example which fits this basic idea.

val idChanger: Reads[JsObject] =
  (__ \ 'id).json.update(of[JsNumber].map{case JsNumber(nb) => JsNumber(nb * 100)})


val picker: Reads[JsValue] = __.json.pick.map{
  case JsArray(arr) => JsArray(arr.map(_.transform(picker).get))
  case v: JsValue =>
    v.transform(
      idChanger andThen (__ \ "children").json.update(picker) orElse
      idChanger
  ).get
}