Reputation: 2866
consider the following json:
{
"type":"A1",
"system":{
"path":"/example.org/FooBar",
"lastModified":"2013-10-01T12:00:00Z"
},
"fields":{
"foo1":["bar1"],
"foo2":["bar2"],
"foo3":["bar3"]
}
}
now, using lift-json, i want to change this json into:
{
"type":"A1",
"system":{
"path":"/example.org/FooBar",
"lastModified":"2013-10-01T12:00:00Z"
},
"fields":{
"foo1":["bar1"],
"foo2":["bar2"],
"foo3":["bar3"]
},
"injected":{
"bar1":"foo1",
"bar2":"foo2"
}
}
so, i tried the following:
scala> val json = parse("""
|{
| "type":"A1",
| "system":{
| "path":"/example.org/FooBar",
| "lastModified":"2013-10-01T12:00:00Z"
| },
| "fields":{
| "foo1":["bar1"],
| "foo2":["bar2"],
| "foo3":["bar3"]
| }
|}""")
json: net.liftweb.json.JValue = JObject(List(JField(type,JString(A1)), JField(system,JObject(List(JField(path,JString(/example.org/FooBar)), JField(lastModified,JString(2013-10-01T12:00:00Z))))), JField(fields,JObject(List(JField(foo1,JArray(List(JString(bar1)))), JField(foo2,JArray(List(JString(bar2)))), JField(foo3,JArray(List(JString(bar3)))))))))
scala> json transform{case JObject(l) => JObject(l ::: List(JField("injected", ("bar1" -> "foo1") ~ ("bar2" -> "foo2"))))}
res0: net.liftweb.json.JsonAST.JValue = JObject(List(JField(type,JString(A1)), JField(system,JObject(List(JField(path,JString(/example.org/FooBar)), JField(lastModified,JString(2013-10-01T12:00:00Z)), JField(injected,JObject(List(JField(bar1,JString(foo1)), JField(bar2,JString(foo2)))))))), JField(fields,JObject(List(JField(foo1,JArray(List(JString(bar1)))), JField(foo2,JArray(List(JString(bar2)))), JField(foo3,JArray(List(JString(bar3)))), JField(injected,JObject(List(JField(bar1,JString(foo1)), JField(bar2,JString(foo2)))))))), JField(injected,JObject(List(JField(bar1,JString(foo1)), JField(bar2,JString(foo2)))))))
scala> Printer.pretty(render(res0))
res1: String =
{
"type":"A1",
"system":{
"path":"/example.org/FooBar",
"lastModified":"2013-10-01T12:00:00Z",
"injected":{
"bar1":"foo1",
"bar2":"foo2"
}
},
"fields":{
"foo1":["bar1"],
"foo2":["bar2"],
"foo3":["bar3"],
"injected":{
"bar1":"foo1",
"bar2":"foo2"
}
},
"injected":{
"bar1":"foo1",
"bar2":"foo2"
}
}
and as you can see, the injected
part, was added into fields
& system
as well.
i just wanted to add it once under the root.
so, what am i doing wrong? and how can i transform the json into the right structure i need?
Upvotes: 7
Views: 1786
Reputation: 139028
If you only need to add a field at a single place, transform
isn't the best tool—you can just use ~
instead:
val newJson = json match {
case obj: JObject =>
obj ~ ("injected" -> ("bar1" -> "foo1") ~ ("bar2" -> "foo2"))
case _ => throw new RuntimeException("Did not receive a JSON object!")
}
If you know for a fact that you'll always parse an object, you could cast json
to JObject
and avoid the matching business here.
Upvotes: 4
Reputation: 15074
The problem you are having is that the partial function defined within transform is matched at all possible levels within the json structure. Since the "system" and "fields" components of the outer JObject are themselves JObjects, they match the partial function, and get transormed as well.
To get the result you are seeking, you will need to make the match more specific, eg:
json transform {case JObject(fields) if (fields contains JField("type", "A1")) =>
JObject(l ::: ...
using some unique information about the outermost object (here, that it has "type" set to "A1").
Alternatively, lift json has a merge capability that I have not dealt with, but which might give what you want:
json merge JObject(JField("injected", ...) :: Nil)
Upvotes: 6