soapUI - Parse JSON Response containing arrays - arrays

Given the following JSON response from a previous test step (request) in soapUI:
{
"AccountClosed": false,
"AccountId": 86270,
"AccountNumber": "2915",
"AccountOwner": 200000000001,
"AccountSequenceNumber": 4,
"AccountTotal": 6,
"ActiveMoneyBeltSession": true,
"CLMAccountId": "",
"CustomerName": "FRANK",
"Lines": [{
"AndWithPreviousLine": false,
"IngredientId": 10000025133,
"OrderDestinationId": 1,
"PortionTypeId": 1,
"Quantity": 1,
"QuantityAsFraction": "1",
"SentToKitchen": true,
"TariffPrice": 6,
"Id": 11258999068470003,
"OriginalRingUpTime": "2014-10-29T07:37:38",
"RingUpEmployeeName": "Andy Bean",
"Seats": []
}, {
"Amount": 6,
"Cashback": 0,
"Change": 0,
"Forfeit": 0,
"InclusiveTax": 1,
"PaymentMethodId": 1,
"ReceiptNumber": "40/1795",
"Tip": 0,
"Id": 11258999068470009,
"Seats": []
}],
"MoaOrderIdentifier": "A2915I86270",
"OutstandingBalance": 0,
"SaveAccount": false,
"ThemeDataRevision": "40",
"TrainingMode": false
}
I have the following groovy script to parse the information from the response:
import groovy.json.JsonSlurper
//Define Variables for each element on JSON Response
String AccountID, AccountClosed, AccountOwner, AccountSeqNumber, AccountTotal, ActMoneyBelt
String CLMAccountID, ThemeDataRevision, Lines, MoaOrderIdentifier, OutstandingBalance, SaveAccount, TrainingMode, CustName, AccountNumber
String AndWithPreviousLine, IngredientId, OrderDestinationId, PortionTypeId, Quantity, SentToKitchen, TariffPrice, Id, OriginalRingUpTime, RingUpEmployeeName, Seats
int AccSeqNumInt
def responseContent = testRunner.testCase.getTestStepByName("ReopenAcc").getPropertyValue("response")
// Create JsonSlurper Object to parse the response
def Response = new JsonSlurper().parseText(responseContent)
//Parse each element from the JSON Response and store in a variable
AccountClosed = Response.AccountClosed
AccountID = Response.AccountId
AccountNumber = Response.AccountNumber
AccountOwner = Response.AccountOwner
AccountSeqNumber = Response.AccountSequenceNumber
AccountTotal = Response.AccountTotal
ActMoneyBelt = Response.ActiveMoneyBeltSession
CLMAccountID = Response.CLMAccountId
CustName = Response.CustomerName
Lines = Response.Lines
/*Lines Variables*/
AndWithPreviousLine = Response.Lines.AndWithPreviousLine
IngredientId = Response.Lines.IngredientId
OrderDestinationId = Response.Lines.OrderDestinationId
PortionTypeId = Response.Lines.PortionTypeId
Quantity = Response.Lines.Quantity
SentToKitchen = Response.Lines.SentToKitchen
TariffPrice = Response.Lines.TariffPrice
Id = Response.Lines.Id
OriginalRingUpTime = Response.Lines.OriginalRingUpTime
RingUpEmployeeName = Response.Lines.RingUpEmployeeName
Seats = Response.Lines.Seats
/*End Lines Variables*/
MoaOrderIdentifier = Response.MoaOrderIdentifier
OutstandingBalance = Response.OutstandingBalance
SaveAccount = Response.SaveAccount
ThemeDataRevision = Response.ThemeDataRevision
TrainingMode = Response.TrainingMode
As you can see above there is an element (Array) called "Lines". I am looking to get the individual element value within this array. My code above when parsing the elements is returning the following:
----------------Lines Variables----------------
INFO: AndWithPreviousLine: [false, null]
INFO: IngredientId: [10000025133, null]
INFO: OrderDestinationId: [1, null]
INFO: PortionTypeId: [1, null]
INFO: Quantity: [1.0, null]
INFO: SentToKitchen: [true, null]
INFO: TariffPrice: [6.0, null]
INFO: Id: [11258999068470003, 11258999068470009]
INFO: OriginalRingUpTime: [2014-10-29T07:37:38, null]
INFO: RingUpEmployeeName: [Andy Bean, null]
INFO: Seats: [[], []]
How can i get the required element from the above, also note the the 2 different data contracts contain the same element "ID". Is there a way to differenciate between the 2.
any help appreciated, thanks.

The "Lines" in the Response can be treated as a simple list of maps.
Response["Lines"].each { println it }
[AndWithPreviousLine:false, Id:11258999068470003, IngredientId:10000025133, OrderDestinationId:1, OriginalRingUpTime:2014-10-29T07:37:38, PortionTypeId:1, Quantity:1, QuantityAsFraction:1, RingUpEmployeeName:Andy Bean, Seats:[], SentToKitchen:true, TariffPrice:6]
[Amount:6, Cashback:0, Change:0, Forfeit:0, Id:11258999068470009, InclusiveTax:1, PaymentMethodId:1, ReceiptNumber:40/1795, Seats:[], Tip:0]
The Response is just one huge map, with the Lines element a list of maps.
Using groovysh really helps here to interactively play with the data, i did the following commands after starting a "groovysh" console:
import groovy.json.JsonSlurper
t = new File("data.json").text
r = new JsonSlurper().parse(t)
r
r["Lines"]
r["Lines"][0]
etc
Edit: In response to your comment, here's a better way to get the entry with a valid AndWithPreviousLine value.
myline = r["Lines"].find{it.AndWithPreviousLine != null}
myline.AndWithPreviousLine
>>> false
myline.IngredientId
>>> 10000025133
If you use findAll instead of find you'll get an array of maps and have to index them, but for this case there's only 1 and find gives you the first whose condition is true.
By using Response["Lines"].AndWithPreviousLine [0] you're assuming AndWithPreviousLine exists on each entry, which is why you're getting nulls in your lists. If the json responses had been reversed, you'd have to use a different index of [1], so using find and findAll will work better for you than assuming the index value.

Related

My react native tensorflow model gives the same prediction every result

I have trained a keras model with 6 classes for CNN Image Recognition. Then, I converted it to tensorflowjs using this command:
tensorflowjs_converter --quantization_bytes 1 --input_format=keras {saved_model_path} {target_path}
which then gives me 2 files (model.json, group1-shard1of1.bin). After adding it to my react native project and test the prediction function, it always returns the same result. I am converting my image to tensor base on this github thread:
const processImagePrediction = async (base64Image: any) => {
const fileUri = base64Image.uri;
const imgB64 = await FileSystem.readAsStringAsync(fileUri, {
encoding: FileSystem.EncodingType.Base64,
});
const imgBuffer = tf.util.encodeString(imgB64, 'base64').buffer;
const raw = new Uint8Array(imgBuffer);
let imageTensor = decodeJpeg(raw);
const scalar = tf.scalar(255);
imageTensor = tf.image.resizeNearestNeighbor(imageTensor, [224, 224]);
const tensorScaled = imageTensor.div(scalar);
//Reshaping my tensor base on my model size (224, 224)
const img = tf.reshape(tensorScaled, [1, 224, 224, 3]);
console.log("IMG: ", img);
const results = model.predict(img);
let pred = results.dataSync();
console.log("PREDICTION: ", pred);
}
I was expecting to have a different result but no matter what image I capture it always returns this result:
LOG IMG: {"dataId": {"id": 23}, "dtype": "float32", "id": 38, "isDisposedInternal": false, "kept": false, "rankType": "4", "scopeId": 6, "shape": [1, 224, 224, 3], "size": 150528, "strides": [150528, 672, 3]} LOG PREDICTION: [-7.7249579429626465, 4.73449182510376, 2.609705924987793, 20.0458927154541, -7.944214344024658, -18.101320266723633]
The numbers somehow change slightly but it retains the highest prediction (which is class number 4).
P.S. I'm new to image recognition so any tips would be appreciated.

How to create an array from 1 to N in TypeScript?

What I want to do is creating an array from 1 to N and call it first_array, then combining it with another array(second array) with the same length and make a new array object like below:
new_array = [
{
"name": "first_array[0]",
"value": second_array[0]
},
{
"name": "first_array[1]",
"value": second_array[2]
},
"name": "first_array[2]",
"value": second_array[2]
];
If you want an array from 1 to N, you can create a new array of length N, fill it with a filler value, then populate the values using their indices with .map.
For example:
const n = 10;
const myArray = new Array(n).fill(null).map((_, i) => i + 1);
with result for myArray:
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
However in this case, it seems you don't need that array if you're just using it alongside another array. Instead you can use the index from that other array (second_array) as values for the "name" key.
Like this:
const newArray = secondArray.map((e, i) => ({
name: i + 1,
value: e,
}));
Example case:
Input
const secondArray = [100, 200, 300];
Result (for newArray)
[
{ name: 1, value: 100 },
{ name: 2, value: 200 },
{ name: 3, value: 300 }
]
First create an array with the maximum number of expected elements. Then reduce this array of empty elements to the merged array:
let array_1th = [1,2,3,4]
let array_2nd = [5,6,7,8];
let merged = Array(Math.max(array_1th.length, array_2nd.length))
.fill().map((_, i) => ({ name: array_1th[i], value: array_2nd[i] }));
console.log(merged);
A small downside of the above example is that two arrays would be created, with the prepared empty array being discarded afterwards.
A slightly nicer solution is to use reduce to mutate the input array directly so that only one array is created:
let array_1th = [1,2,3,4]
let array_2nd = [5,6,7,8];
let merged = Array(Math.max(array_1th.length, array_2nd.length)).fill()
.reduce((_, __, i, array) => (array[i] = { name: array_1th[i], value: array_2nd[i] }, array), null);
console.log(merged);

Angular 6 compare two JSON Arrays

I am fetching notifications using API. Now here is the scenario:
1- I called the API, got 2 records and stored them in local variable (notifications) to show in view.
[{"id": 1, "notification": "bla"}, {"id": 2, "notification": "bla bla"}]
2- I am calling the same API to check for new notification after every 5 seconds. This time I need to compare the API response with the local variable, so if no new notification (different id) is in the record, don't push in local variable, other push.
I have tried something like this:
var val = JSON.parse(data);
if( val.length > 0 ) {
for( var i = 0; i < val.length; i++ ) {
this.notifications.forEach(element => {
if( element.id != val[i].id ) {
this.notifications.push(val[i]);
}
});
}
}
But its adding duplicate records. Any help would be appreciated.
Thanks
You need to use Array.find() to find the duplicate object in the val array.
var notifications = [{"id": 1, "notification": "bla"}, {"id": 2, "notification": "bla bla"}];
var data = `[{"id": 1, "notification": "bla"}, {"id": 4, "notification": "bla bla bla"}]`
var val = JSON.parse(data);
if( val.length > 0 ) {
val.forEach((obj)=>{
var existNotification = notifications.find(({id}) => obj.id === id);
if(!existNotification){
notifications.push(obj);
}
});
}
console.log(notifications);
Currently, you are getting duplicated element because the id value is compared against all the existing id values in notifications array. So, if one of the id do not match with another, it is pushed immediately into the notifications array. So, the better way and simple way is to use a find operation on the array to check the existing object.
A more robust way to handle this could be by using map in JS.
Rather than iterating the notifications (size = m) for every object in the data (size = n) would result in more time complexity of O(m x n).
Hence it could be done in O(n) as below:-
var notifications = new Map();
// assuming you get this at the beginning
var data1 = `[{"id": 1, "notification": "bla"}, {"id": 2, "notification": "bla bla"}]`;
checkAndAddNotification(data1);
// assuming you get this at the second time
var data2 = `[{"id": 1, "notification": "bla"}, {"id": 4, "notification": "bla bla bla"}]`
checkAndAddNotification(data2);
function checkAndAddNotification(data){
var val = JSON.parse(data);
if (val){
val.forEach((obj)=>{
var existNotification = notifications.get(obj.id);
if(!existNotification){
notifications.set(obj.id, obj);
}
});
}
}
console.log(notifications);
notifications.forEach((notification) => console.log(notification));
Please open the browser console as well while running the code.
Even if you plan to iterate over the map, the order would be preserved in the order the objects were inserted. Please look here for more.

How can I convert vectors into JSON and then post it in a service

I need to convert this two vectors into a JSON with some other fields:
x_axis <- c("Dogs","Cats","Birds")
y_axis <- c(5,9,3)
The JSON must also contain these two fields:
user_id=3
model_number=4
The JSON to post must have this format:
{
"user_id":3,
"model_number": 4,
"data": [{
"x_axis": "Dogs",
"y_axis": 5
},{
"x_axis": "Cats",
"y_axis": 9
},{
"x_axis": "Birds",
"y_axis": 3
}]
}
You can use jsonlite...
library(jsonlite)
x_axis <- c("Dogs","Cats","Birds")
y_axis <- c(5,9,3)
user_id=3
model_number=4
data <- data.frame(x_axis=x_axis,y_axis=y_axis)
toJSON(list(user_id=user_id,
model_number=model_number,
data=data),
dataframe="rows",
auto_unbox = TRUE)
{"user_id":3,
"model_number":4,
"data":[{"x_axis":"Dogs","y_axis":5},
{"x_axis":"Cats","y_axis":9},
{"x_axis":"Birds","y_axis":3}]}
You can create that output using purrr and jsonlite
library(purrr)
library(jsonlite)
toJSON(list(
user_id = user_id,
model_number = model_number,
data = map2(x_axis, y_axis, ~list(x_axis=.x, y_axis=.y))
), auto_unbox = TRUE)
Basically we just create a named list in such a way that mirrors your desired output shape. Named lists result in {} objects and unnamed lists become [] arrays.

ImmutableJS Map, how to iterate over a map and return a modified result

I am trying to remove the keys listed in the skipheaders array from the submissionsInForm.
const skipHeaders = [ 'layout', 'modules', 'enabled', 'captcha', 'settings'];
submissionsInForm.map((submission) => {
const updatedSubmission = submission.deleteAll(skipHeaders);
return updatedSubmission;
});
That code doesn't seem to be working, as it is returning the full data. Is there anyway to achieve this without having to converting to Vanilla JS?
blacklist
You could use Map#filter to remove any key/value pairs where the key appears in the blacklist
// where Map is Immutable.Map
const m = Map({a: 1, b: 2, c: 3, d: 4})
const blacklist = ['a', 'b']
m.filter((v,k) => !blacklist.includes(k))
// => {"c": 3, "d": 4}
whitelist
Your object is called submissionsInForm so I'm guessing these are user-supplied values. In such a case, I think it is much better to whitelist your fields instead of blacklisting like we did above
Notice we'll add some more fields to the input m this time but our result will be the same, without having to change the whitelist. This is good when you want to explicitly declare which fields the user can submit – all other fields will be rejected.
const m = Map({a: 1, b: 2, c: 3, d: 4, admin: 1, superuser: true})
const whitelist = ['c', 'd']
m.filter((v,k) => whitelist.includes(k))
// => {"c": 3, "d": 4}

Resources