JsPath: navigate backward - json

let me explain the problem that I'm facing:
I have two JSON objects, let's call them js1 and js2, I need to update js1 using "parts" of js2 object, and to do that I need to identify where this parts that needs to be updated are in js1.
To do that, I'm using a function that, for a certain input, return the full JsPath from root to the input value, and I get back a JsPath like this:
/priceLists(1)/sections(0)/items(0)(0)/itemIdentifier
what I need to do is navigate backward one step, to obtain a JsPath like
/priceLists(1)/sections(0)/items(0)(0)
I'm probably very dumb (and with not so much experience with Scala in general) but I can't find any way to do that.
The only way I found to get rid of that last part of the path is to transform JsPath into a list of PathNode, but then I don't know how to transform back that list of PathNodes into a JsPath.
I'm using Play 2.6 and Scala 2.11.8.

Related

deleting JSON records using JsonDataObjects

I'm using the TJsonDataObjects Delphi component (https://github.com/ahausladen/JsonDataObjects). I am using it as the data store for what is is displayed in a editable TreeView. In the treeview I store the "path" using a JsonPath string. When the user modifies the values in the Treeview, the path property allows me locate the record by path and modify it via the component path property.
My issue is when a user wants to delete a record, I need to remove it from the JSON file. It does note seem like there is a simple way to do this via its "path. I expect I could trim off the item from the path to gets it parent and then delete it by "name" or "index" if an array. I was hoping there might just be an easier way before I start to code this up.
On a similar node, I didn't find any way to extract the text path of a given item. While it can modify or locate a node by path, there does not seem to be a way to get the actual path so I'm doing that manually as I parse the JSON file (yuck). Anyone have a better solution?
For example, this is the path of the "value" property in the JSON below: Level1.Level2.Level3
{
"Level1": {
"Level2": {
"Level3": "value"
}
}
}
In TJsonDataObjects you can set the path with:
Json.Path['Level1.Level2.Level3'] := "value";
//or
Json['Level1']['Level2']['Level3'] := "value";
Or retrieve it with:
prop := Json.Path['Level1.Level2.Level3'];
// or
prop := Json['Level1']['Level2']['Level3'];
So if you want to remove Level3, it would be nice if there was some simple function like Json.DeletePath('Level1.Level2.Level3');. As far as I can tell, there is nothing that does this. Since this is a very complex unit, I thought someone might have an easy answer that I overlooked. I have coded a way around this (as described above).
As to the second question, while you can access a value by its path, there is no function to "return" a path from a given node. And yes, I can and do build it as I go along, it would be handy as that way it remains consistent in its format of the JsonPath.

Add/Remove elements in a JSON Array in Scala/Play

I have a pretty complex JSON object that contains, among other things, some JSON arrays that I need to update, removing and adding elements.
To do that I'm trying to use a JsPath that point directly to the object inside the array that I need to remove, something like:
/priceLists(1)/sections(0)/items(0)
to remove the element I tried to use json.prune and it doesn't work, I get this error: error.expected.jsobject
Would would be the best way to do that?
Your question is lacking a precise context (i.e., structure of your json data), but let's do with what we have.
The error message you get is clear, you can only call prune on a json object, to prune one of its values. You can't use it to prune an element of a json array.
I can only advise you to use json.update, stating that like prune, update only works on json objects. In the body of the update, work on your arrays as you usually do with scala/java data types.
__.json.update(__.reads[JsArray].map { jsArray =>
val removedElement = JsArray(jsArray.value.filter(_ == ???))
val addedElement = removedElement :+ JsBoolean(true)
addedElement
})

clojure.data.json/write-str: specifying a key function for placing values into aggregate arrays

Suppose I have a simple map, example-map:
(def example-map {"s" {"f" "g"}
"m" {"r" "q"}})
I can use clojure.data.json/write-str to JSON-ify this map as such:
(clojure.data.json/write-str example-map) =>
"{\"s\":{\"f\":\"g\"},\"m\":{\"r\":\"q\"}}"
I'd like to conditionally place some of the values into lists according to the value of their keys.
write-str provides an optional :key-fn, which applies some function to key value pairs. For example, the desired function might specify that all values associated with entries that match "s" are placed in lists.
(clojure.data.json/write-str example-map :key-function desired-function) =>
"{\"s\":[{\"f\":\"g\"}],\"m\":{\"r\":\"q\"}}"
Does anyone know how to specify such a key function that checks for membership of a key in a set and places the values associated with members into an array rendered in the output JSON?
Like your previous question, this is not a job for the JSON parser. You don't need to rely on write-time features of your JSON library to adjust the shape of your JSON maps. Instead, you have a fully functional Turing complete language at your disposal: Clojure! If the maps don't already look the way you want them to be output, then write a function that takes one Clojure map as input and produces a different one as output; then ask your JSON library to write the output map, without any special rules for fiddling with the output.
Now, as it happens this particular JSON library does provide an option named value-fn (not key-function as you claim) to let you modify a value in a map based on its key. So you could use that, in which case you simply need to write a function with a signature like:
(fn [k v]
(...compute new value...))
There are many ways you could write such a function, but they are all entirely divorced from your JSON parser. If you need help writing it, mention some specific things you need help with, so you can get a clear explanation for the part of the process that is actually giving you trouble.

Deserialize an anonymous JSON array?

I got an anonymous array which I want to deserialize, here the example of the first array object
[
{ "time":"08:55:54",
"date":"2016-05-27",
"timestamp":1464332154807,
"level":3,
"message":"registerResourcePath ('', '/sap/bc/ui5_ui5/ui2/ushell/resources/')",
"details":"","component":"sap.ui.ModuleSystem"},
{"time":"08:55:54","date":"2016-05-27","timestamp":1464332154808,"level":3,"message":"URL prefixes set to:","details":"","component":"sap.ui.ModuleSystem"},
{"time":"08:55:54","date":"2016-05-27","timestamp":1464332154808,"level":3,"message":" (default) : /sap/bc/ui5_ui5/ui2/ushell/resources/","details":"","component":"sap.ui.ModuleSystem"}
]
I tried deserializing using CL_TREX_JSON_SERIALIZER, but it is corrupt and does not work with my JSON, here is why
Then I tried /UI2/CL_JSON, but it needs a "structure" that perfectly fits the object given by the JSON Object. "Structure" means in my case an internal table of objects with the attributes time, date, timestamp, level, messageanddetails. And there was the problem: it does not properly handle references and uses class description to describe the field assigned to the field-symbol. Since I can not have a list of objects but only a list of references to objects that solution also doesn't works.
As a third attempt I tried with the CALL TRANSFORMATION as described by Horst Keller, but with this method I was not able to read in an anonymous array, and here is why
My major points:
I do not want to change the JSON, since that is what I get from sap.ui.log
I prefere to use built-in functionality and not a thirdparty framework
Your problem comes out not from the anonymity of array, but from the awkwardness of SAP JSON (De)serializer, which doesn't respect double quotes, which enclose JSON attributes. The issue is thoroughly described in this answer.
If you don't want to change your JSON on-the-fly, the only way you have is to change CL_TREX_JSON_DESERIALIZER class like this.
/UI5/CL_JSON_PARSER parses JSONs with unknown format.
Note that it's got "for internal use" written on it so many times that you probably should take it seriously and clone its code to fixate it.

Accessing nested list items in an interpolated string using dot notation in Scala

I'm trying to pass a value via JSON that I am having trouble accessing. We have a data structure (that was obviously not built by me otherwise I would likely understand it) that looks something like this when sent to the browser:
{Foo(Bar(List(Baz(List(G3),w))),G3,None)}
This is sent via a JSON write method, but the originating Scala line looks like:
val hint = Some(s"{$question}") where $question is of type Foo.
I've tried using dot notation to access the list items in ways that I thought would work:
val hint = Some(s"{$question.Bar.Baz})"
val hint = Some(s"{$question.Bar(0).Baz(0)"})
It's the deepest G3 I wanted to strip out and send, but instead the JSON object comes through looking like:
{Foo(Bar(List(Baz(List(G3),w))),G3,None)}.Bar.Baz or
{Foo(Bar(List(Baz(List(G3),w))),G3,None)}.Bar(0).Baz(0)
I must be fundamentally missing something about the data structures involved here.
I think you're just using the wrong syntax. The $ needs to come before the {} and the {} is necessary for any expression more complicated than just a variable name:
s"${question.bar(0).baz(0)}"