Lifting-json-manipulation - adding to the right place

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 to:

 { "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 injected been added to fields and system . I just wanted to add it once under the root.

So what am I doing wrong? and how can I convert json to the structure I need?

+6
source share
2 answers

The problem you are facing is that the partial function defined in the conversion maps at all possible levels within the json structure. Since the β€œsystem” and β€œfield” components of the external JObject themselves are JObjects, they correspond to a partial function and are also translated.

To get the result you are looking for, you will need to make the match more specific, for example:

 json transform {case JObject(fields) if (fields contains JField("type", "A1")) => JObject(l ::: ... 

using some unique information about the outermost object (here it has a "type" set to "A1").

Alternatively, the json elevator has a merge option, which I could not handle, but which can give what you want:

 json merge JObject(JField("injected", ...) :: Nil) 
+5
source

If you only need to add the field in one place, transform is not 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 that you will always parse the object, you can drop json in JObject and avoid the proper work here.

+4
source

Source: https://habr.com/ru/post/955016/


All Articles