Are my eyes deceiving me or can I not update a nested node with a JsPath containing an array element in between? (e.g. /a/b(0)/c)
val pnJson = Json.parse("""{"a": {"b": [ {"c": { "d": 1 } } ] } } """)
val pnJsPath = (__ \ "a" \ "b")(0) \ "c"
val pnTrans = pnJsPath.json.update ( __.read[JsObject].map{ _ ++ Json.obj( "e" -> 2 )} )
pnJson.transform(pnTrans)
//result: java.lang.RuntimeException: expected KeyPathNode
If I cant use __.json.update, How can I accomplish this? Trying to accomplish this with immutablity.
The short answer is you can't do that with JsPath
. That ticket mentions using the JsZipper library as a better way to manipulate JSON. If you choose to use it, you can do:
scala> import play.api.libs.json.extensions._
import play.api.libs.json.extensions._
scala> import play.api.libs.json.monad.syntax._
import play.api.libs.json.monad.syntax._
scala> val pnJson = Json.parse("""{"a": {"b": [ {"c": { "d": 1 } } ] } } """)
pnJson: play.api.libs.json.JsValue = {"a":{"b":[{"c":{"d":1}}]}}
scala> val pnJsPath = (__ \ "a" \ "b")(0) \ "c"
pnJsPath: play.api.libs.json.JsPath = /a/b(0)/c
scala> pnJson.update(pnJsPath, _.set(__ \ "e" -> JsNumber(2)))
res0: play.api.libs.json.JsValue = {"a":{"b":[{"c":{"d":1,"e":2}}]}}
Otherwise, your best bet is to break your task into two parts, the first part being parsing the array and the second part being transforming it into a new array with modified contents.