Changing an immutable object F# - json

I think the title of this is wrong but can't create a title that reflects, in the abstract, what I want to achieve.
I am writing a function which calls a service and retrieves data as a JSON string. The function parses the string with a JSON type provider. Under certain conditions I want to amend properties on that JSON object and then return the string of the amended object. So if the response from the call was
{"property1" : "value1","property2" : "value2", "property3": "value3" }
I want to change property3 to a new value and then return the JSON string.
If the JsonProvider was mutable this would be an exercise like:
type JsonResponse =
JsonProvider<""" {"property1" : "value1",
"property2" : "value2",
"property3": "value3" } """>
let jsonResponse = JsonResponse.Parse(response)
jsonResponse.Property3 <- "new value"
jsonResponse.ToString()
However, this does not work as the property cannot be set. I am trying to ascertain the best way to resolve this. I am quite happy to initialise a new object based on the original response but with amended parameters but I am not sure if there is an easy way to achieve this.
For reference, the JSON object is much more involved than the flat example given and contains a deep hierarchy.

Yes, you would need to create a new object, changing the bits you want and using the existing object's values for the rest. We added write APIs for both the XML and JSON type providers a while back. You will notice the types representing your JSON have constructors on them. You can see an example of this in use at the bottom of this link

Related

Parsing Vector to Array String

I'm new to Rust.
I try to write a websocket client.
This is my format message:
"[integer, "string", object]"
Is there away to store all value in Vector something like:
let msg: Vec<interface> = vec![123, "event", AnyObject{}];
How to convert it into string and vice versa.
Thanks in advance
Conceptually speaking you want to use an enum. The type of enums used in rust are called tagged unions. Essentially you can think of them as enums which can hold data.
enum Interface {
Int(i32),
String(&'static str),
Object(AnyObject),
// etc
}
// You can then create a vec of different enum variants
let msg: Vec<Interface> = vec![Interface::Int(123), Interface::String("event"), Interface::Object(AnyObject{})];
Assuming you are referring to JSON, then the recommended solution is to use serde with serde_json. serde_json provides a Value enum you can use to represent JSON data in an unknown layout.
// Copied from serde_json docs
enum Value {
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<Value>),
Object(Map<String, Value>),
}
However, you don't need to use Value directly (unless you want to) since serde_json provides a macro to make this easier by letting you format your code like JSON.
use serde_json::{json, Value};
let msg: Value = json!([123, "event", {}]);
// You can then serialize a Value into JSON format
println!("{:?}", msg.to_string());
// Output: "[123,\"event\",{}]"
I recommend reading through the overview since they have a bunch of convenient ways for working with JSON.

How do I parse JSON in Go where array elements have more than one type?

How can I parse a JSON response from https://api.twitchinsights.net/v1/bots/online to an array in Go and iterate over every entry?
I dont understand the struct because there are no keys only values...
Can anyone please help and explain how this works?
I've mapped it but then I get something like
map[_total:216 bots:[[anotherttvviewer 67063 1.632071051e+09] [defb 26097 1.632071051e+09] [commanderroot 17531 1.632071048e+09] [apparentlyher 16774 1.63207105e+09]...
But I cant iterate over the map.
Because the API you're working with returns data where it could be a string or a number (in the array of arrays property bots), you'll need to use []interface{} as the type for each element of that array because the empty interface (https://tour.golang.org/methods/14) works for any type at run time.
type response struct {
Bots [][]interface{} `json:"bots"`
Total int `json:"_total"`
}
Then, as you iterate through each item in the slice, you can check its type using reflection.
It would be ideal for the API to return data in a schema where every JSON array element has the same JSON type as every other element in its array. This will be easier to parse, especially using statically typed languages like Go.
For example, the API could return data like:
{
"bots": [
{
"stringProp": "value1",
"numberProps": [
1,
2
]
}
],
"_total": 1
}
Then, you could write a struct representing the API response without using the empty interface:
type bot struct {
StringProp string `json:"stringProp"`
NumberProps []float64 `json:"numberProps"`
}
type response struct {
Bots []bot `json:"bots"`
Total int `json:"_total"`
}
But sometimes you're not in control of the API you're working with, so you need to be willing to parse the data from the response in a more dynamic way. If you do have control of the API, you should consider returning the data this way instead.

Passing json string as an input to one of the parameters of a POST request body

I need to pass a json string as a value to one parameter of a POST request body. My request body looks like this:
"parameter1":"abc",
"parameter2":"def",
"parameter3": "{\"id\":\"\",\"key1\":\"test123\",\"prod1\":{\"id\":\"\",\"key3\":\"test123\",\"key4\":\"12334\",\"key5\":\"3\",\"key6\":\"234334\"},\"prod2\":{\"id\":\"\",\"key7\":\"test234\",\"key8\":1,\"key9\":true}}\"",
"parameter4":false,
"parameter5":"ghi"
}
For parameter3 I need to be pass a string value in json format. The json file is located in my local system and is a huge file, so it would make sense if I can pass it as a jmeter variable. I tried as below:
{
"parameter1":"abc",
"parameter2":"def",
"parameter3": "${jsonObj}",
"parameter4":false,
"parameter5":"ghi"
}
after adding a JSR223 preprocessor with the code below:
import org.apache.jmeter.util.JMeterUtils;
String fileContents = new File("path to json//myJson.json").getText('UTF-8');
vars.put("fileContents",fileContents);
var deltaJson = vars.get("fileContents");
var jsonObj = JSON.parse(deltaJson);
vars.put("jsonObj", JSON.stringify(jsonObj));
But I get below error:
exceptions":{"exceptionType":"System.JSONException","exceptionMessage":"Unexpected character ('$' (code 36)): expected a valid value (number, String, array, object, 'true', 'false' or 'null') at input location [1,2]"}
Can anyone help me in resolving this issue?
There is an easier way of doing this, JMeter comes with __FileToString() function so you can achieve the same much faster and without having to do any scripting
Something like:
{
"parameter1": "abc",
"parameter2": "def",
"parameter3": ${__FileToString(path to json//myJson.json,UTF-8,jsonObj)},
"parameter4": false,
"parameter5": "ghi"
}
Also be aware of the following facts:
the recommended language for using in JSR223 Test Elements is Groovy as it provides the maximum performance
you seem to be using JSON object which cannot be used outside of the browser context therefore your code fails to generate proper JSON hence your request fails as you're passing ${jsonObj} as it is, the substitution doesn't happen, you can look to jmeter.log file yourself and see the exact reason of your script failure

Get length/size of json data

I have use the following codes to get my json data with certain nodes.
console.log(Object.keys(data.Top["person"]).length);
It is work fine in following structure of json data array:
data:{"Top":{"person":[{"A":"a","B":"b"},{"A":"a","B":"b"}]}}
However when the person only have one nodes, it always show the answer 2 to me, it should be answer 1.
data:{"Top":{"person":{"A":"a","B":"b"}}}
Is it possible to solve this error?
length property is supported by type array.
data:{"Top":{"person":[{"A":"a","B":"b"},{"A":"a","B":"b"}]}} in case of this person is array enclosed with [ ]
Where as for data:{"Top":{"person":{"A":"a","B":"b"}}} person is just an object. Hence length is undefined for it.
If you are creating json out of string or formatting it make sure to include [ and ] for person attribute.
JSFiddle
https://jsfiddle.net/d6pqnckh/
Also use JSON formatter to test JSON structure.
UPDATE
Since you are not sure of JSON structure. What you could do is before accessing length of person check if it is an array or object.
if(Object.prototype.toString.call(data.Top.person) === '[object Array]')
alert(data.Top.person.length);
//It is an array
else
alert("I AM OBJECT"); //It is of an object type
Updated Fiddle: https://jsfiddle.net/wys7awuz/
To make it an array regardless https://jsfiddle.net/ofkboh6k/
var p = data.Top.person;
delete data.Top.person;
data.Top.person = [];
data.Top.person.push(p);
alert(data.Top.person.length);
Include this in else part of condition. It will make it an array.
length works for type array.
change your JSON to
data:{"Top":{"person":[{"A":"a","B":"b"}]}}

Parse a large file of non-schematized json using Jackson?

I have a very large .json file on disk. I want to instantiate this as a Java object using the Jackson parser.
The file looks like this:
[ { "prop1": "some_value",
"prop2": "some_other_value",
"something_random": [
// ... arbitrary list of objects containing key/value
// pairs of differing amounts and types ...
]
},
// ... repated many times ...
{
}
]
Basically it's a big array of objects and each object has two string properties that identify it, then another inner array of objects where each object is a random collection of properties and values which are mostly strings and ints, but may contain arrays as well.
Due to this object layout, there isn't a set schema I can use to easily instantiate these objects. Using the org.json processor requires attempting to allocate a string for the entire file, which often fails due to its size. So I'd like to use the streaming parser, but I am completely unfamiliar with it.
What I want in the end is a Map where the String is the value of prop1 and SomeObject is something that holds the data for the whole object (top-level array entry). Perhaps just the JSON which can then be parsed later on when it is needed?
Anyway, ideas on how to go about writing the code for this are welcome.
Since you do not want to bind the whole thing as single object, you probably want to use readValues() method of ObjectReader. And if structure of individual values is kind of generic, you may want to bind them either as java.util.Maps or JsonNodes (Jackson's tree model). So you would do something like:
ObjectMapper mapper = new ObjectMapper();
ObjectReader reader = mapper.reader(Map.class); // or JsonNode.class
MappingIterator<Map> it = reader.readValues(new File("stuff.json"));
while (it.hasNextValue()) {
Map m = it.nextValue();
// do something; like determine real type to use and:
OtherType value = mapper.convertValue(OtherType.class);
}
to iterate over the whole thing.