Deserialize multi JSON string with Play JSON library - json

I'm writing a server that need to parse JSON strings uploaded by clients. Currently I'm using Play JSON lib. For example:
import play.api.libs.json._
def parseJSON(jsonString: String) = {
val jsv = Json.parse(jsonString)
jsv
}
Considering a client uploaded a JOSN string of {"key1": 1}. After the server received the entire string, just simple invoke the parseJSONmethod, everything will be done.
However, if a client uploaded TWO JSON strings, {"key2": 2} and {"key3": 3}, and due to the bad network, these two JSON strings reach the server at the same time. The server will get a long string of {"key2": 2}{"key3": 3} (The server can not know it contains two JSON strings before parsing). if I invoke the parseJSON method and pass the entire string, only the first JSON value {"key2": 2} will be returned. The second one {"key3": 3} will be ignored.
So, how can I parse the second JSON string? Is there a way to know how many Chars are used when parsing the first JSON string?

val jsonString2 = """{
"key1": 1,
"key2": 2
}
{
"key3": 3,
"""
I think this is not valid JSON value, please make your question cleaner as possible so we can help :)

Related

How to split an array of JSON documents into fixed size chunks?

I have a JSON document representing an array of 100 objects and I need to process this document in batches, e.g. 10 objects per batch.
def text = '[{1st},{2nd},{3rd},{4th},...{100th}]'
def json = new groovy.json.JsonSlurper().parseText(text)
Now I need to take first 10 elements from text ([{1st},{2nd},..{10th}]) and post them into web service, then another 10 ([{11th},{12th}...{20th}]) and so on.
I've tried this in C# but not able to do that in Groovy.
Anyone suggest me the best way to send batches of json and every time total number of json has changed dynamically?
Groovy adds Iterable.collate(int size) method via DefaultGroovyMethods class and you can use it to split your input array into n-size chunks, e.g.
['a','b','c','d','e'].collate(3) == [['a','b','c'], ['d','e']]
Consider following example:
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
final String text = '[{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, {"id": 6}]'
final List<Map> json = new JsonSlurper().parseText(text) as List<Map>
json.collate(2).each { part ->
final String out = JsonOutput.toJson(part)
println "Sending following JSON object: ${out}"
}
Run in Groovy web console
Here we have a JSON array of 6 objects. We parse this JSON to a List<Map> object and then we split into chunks of size 2 and prepare JSON for later execution. I used only 6 objects as an illustration, however it doesn't matter if the initial list contains 100 objects and we split into chunks of size 10 - the algorithm is the same.
It can be generalized and described in following steps:
Parse initial JSON array of objects
Split an array into chunks of size 10
Format chunk of 10 objects into JSON String
Process JSON document
The example shown above produces following output:
Sending following JSON object: [{"id":1},{"id":2}]
Sending following JSON object: [{"id":3},{"id":4}]
Sending following JSON object: [{"id":5},{"id":6}]

Erlang: Parse string to json

I have the following string:
"{\"headers\":[\"CNPJ\",\"PDF\",\"error\"],\"rows\":[[\"17192451000170\",\"FILE:application/pdf;170286;\",null],[\"234566767544\",\"FILE:application/pdf;456378;\",null],[\"233456767544\",\"FILE:application/pdf;456378;\",null]]}"
how do I parse it to a normal Json format?
meaning:
{"rows" :[
{"CNPJ":"17192451000170","PDF":"FILE:application/pdf;170286;","error":null},
{"CNPJ":"17192451000170","PDF":"FILE:application/pdf;170286;","error":null},
{"CNPJ":"17192451000170", "PDF":"FILE:application/pdf;170286;,"error":null"}
]}
or any other json format
This is already a valid JSON format.
If you just want to strip \ then you can simply:
(hbd#crayon2.yoonka.com)31> JsonOrg = <<"{\"headers\":[\"CNPJ\",\"PDF\",\"error\"],\"rows\":[[\"17192451000170\",\"FILE:application/pdf;170286;\",null],[\"234566767544\",\"FILE:application/pdf;456378;\",null],[\"233456767544\",\"FILE:application/pdf;456378;\",null]]}">>.
<<"{\"headers\":[\"CNPJ\",\"PDF\",\"error\"],\"rows\":[[\"17192451000170\",\"FILE:application/pdf;170286;\",null],[\"234566767544\",\"FI"...>>
(hbd#crayon2.yoonka.com)32> io:format("~s~n", [binary_to_list(JsonOrg)]).
{"headers":["CNPJ","PDF","error"],"rows":[["17192451000170","FILE:application/pdf;170286;",null],["234566767544","FILE:application/pdf;456378;",null],["233456767544","FILE:application/pdf;456378;",null]]}
ok
You can also parse back and forth between Json and Erlang. I tested that with the yajler decoder:
(hbd#crayon2.yoonka.com)43> {ok, Parsed} = yajler:decode(<<"{\"headers\":[\"CNPJ\",\"PDF\",\"error\"],\"rows\":[[\"17192451000170\",\"FILE:application/pdf;170286;\",null],[\"234566767544\",\"FILE:application/pdf;456378;\",null],[\"233456767544\",\"FILE:application/pdf;456378;\",null]]}">>).
{ok,[{<<"headers">>,[<<"CNPJ">>,<<"PDF">>,<<"error">>]},
{<<"rows">>,
[[<<"17192451000170">>,<<"FILE:application/pdf;170286;">>,
undefined],
[<<"234566767544">>,<<"FILE:application/pdf;456378;">>,
undefined],
[<<"233456767544">>,<<"FILE:application/pdf;456378;">>,
undefined]]}]}
(hbd#crayon2.yoonka.com)44> Json = binary:list_to_bin(yajler:encode(Parsed)).
<<"{\"headers\":[\"CNPJ\",\"PDF\",\"error\"],\"rows\":[[\"17192451000170\",\"FILE:application/pdf;170286;\",\"undefined\"],[\"2345667675"...>>
Yajler is an Erlang NIF so it is using a C library, in this case called yajl, to do the actual parsing, but I imagine a similar result you would get from other Erlang applications that can parse JSON.

Json handling in ROBOT

I have a Json file in which there is a field which I need to edit and save the file for next usage.
But the field which I need to edit is as shown below,
The value I need to assign fr the field is generated Randomly in run time which i'll be capturing in a variable and pass it to this json specific key "dp" then save the json.
The saved json will be used for REST POST url.
{
"p": "10",
"v": 100,
"vt": [
{
"dp": "Field to be edited"(integer value) ,
]
}
The simplest solution would be to write a python keyword that can change the value for you. However, you can solve this with robot keywords by performing the following steps:
convert the JSON string to a dictionary
modify the dictionary
convert the dictionary back to a JSON string
Convert the JSON string to a dictionary
Python has a module (json) for working with JSON data. You can use the evaluate keyword to convert your JSON string to a python dictionary using the loads (load string) method of that module.
Assuming your JSON data is in a robot variable named ${json_string}, you can convert it to a python dictionary like this:
${json}= evaluate json.loads('''${json_string}''') json
With the above, ${json} now holds a reference to a dictionary that contains all of the json data.
Modify the dictionary
The Collections library that comes with robot has a keyword named set to dictionary which can be used to set the value of a dictionary element. In this case, you need to change the value of a dictionary nested inside the vt element of the JSON object. We can reference that nested dictionary using robot's extended variable syntax.
For example:
set to dictionary ${json["vt"]} dp=the new value
With that, ${json} now has the new value. However, it is still a python dictionary rather than JSON data, so there's one more step.
Convert the dictionary back to JSON
Converting the dictionary back to JSON is the reverse of the first step. Namely, use the dumps (dump string) method of the json module:
${json_string}= evaluate json.dumps(${json}) json
With that, ${json_string} will contain a valid JSON string with the modified data.
Complete example
The following is a complete working example. The JSON string will be printed before and after the substitution of the new value:
*** Settings ***
Library Collections
*** Test Cases ***
Example
${json_string}= catenate
... {
... "p": "10",
... "v": 100,
... "vt": {
... "dp": "Field to be edited"
... }
... }
log to console \nOriginal JSON:\n${json_string}
${json}= evaluate json.loads('''${json_string}''') json
set to dictionary ${json["vt"]} dp=the new value
${json_string}= evaluate json.dumps(${json}) json
log to console \nNew JSON string:\n${json_string}
For reading and writing data to and from file I am using OperatingSystem library
${json} Get Binary File ${json_path}nameOfJsonFile.json
It works for me on API testing, to read .json and POST, like here
*** Settings ***
Library Collections
Library ExtendedRequestsLibrary
Library OperatingSystem
*** Variables ***
${uri} https://blabla.com/service/
${json_path} C:/home/user/project/src/json/
*** Test Cases ***
Robot Test Case
Create Session alias ${uri}
&{headers} Create Dictionary Content-Type=application/json; charset=utf-8
${json} Get Binary File ${json_path}nameOfJsonFile.json
${resp} Post Request alias data=${json} headers=${headers}
Should Be Equal As Strings ${resp.status_code} 200
For integer values in JSON, the other answers did not work for me.
This worked:
${json}= Catenate { "p": "10", "v": 100, "vt": { "dp": "Field to be edited" } }
${value} Set Variable 2 #the value you want
${value} Convert To Integer ${value}
${json}= Evaluate json.loads('''${json}''') json
Set To Dictionary ${json["vt"]} dp=${value}
${json}= Evaluate json.dumps(${json}) json
Log ${json}
Convert To Integer was required, otherwise the value is still in string "${value}"

Convert scala list to Json object

I want to convert a scala list of strings, List[String], to an Json object.
For each string in my list I want to add it to my Json object.
So that it would look like something like this:
{
"names":[
{
"Bob",
"Andrea",
"Mike",
"Lisa"
}
]
}
How do I create an json object looking like this, from my list of strings?
To directly answer your question, a very simplistic and hacky way to do it:
val start = """"{"names":[{"""
val end = """}]}"""
val json = mylist.mkString(start, ",", end)
However, what you almost certainly want to do is pick one of the many JSON libraries out there: play-json gets some good comments, as does lift-json. At the worst, you could just grab a simple JSON library for Java and use that.
Since I'm familiar with lift-json, I'll show you how to do it with that library.
import net.liftweb.json.JsonDSL._
import net.liftweb.json.JsonAST._
import net.liftweb.json.Printer._
import net.liftweb.json.JObject
val json: JObject = "names" -> List("Bob", "Andrea", "Mike", "Lisa")
println(json)
println(pretty(render(json)))
The names -> List(...) expression is implicitly converted by the JsonDSL, since I specified that I wanted it to result in a JObject, so now json is the in-memory model of the json data you wanted.
pretty comes from the Printer object, and render comes from the JsonAST object. Combined, they create a String representation of your data, which looks like
{
"names":["Bob","Andrea","Mike","Lisa"]
}
Be sure to check out the lift documentation, where you'll likely find answers to any further questions about lift's json support.

KRL: Parsing string as JSON

After using http:get(), I receive back a string from picking the "content" from the hash:
response = http:get(webservice_url, {"key1": value1, "key2": value2});
json_resp = response.pick("$..content");
However, since json_resp is a string and not an actual JSON object, I can't run a command like this:
value = json_resp.pick("$..string");
Is there a way to tell KRL that I want to parse json_resp as JSON? An eval() or something, perhaps?
The decode() operator does just what you want. It operates on a JSON string, attempting to convert it to a native KRL object. Note that KRL also has encode() which operates on a native KRL object and returns a JSON string representation of that object.
response = http:get(webservice_url, {"key1": value1, "key2": value2});
json_resp = response.pick("$..content").decode();
value = json_resp.pick("$..string");
// will work since json_resp is now a native KRL object