My Camel route is calling a REST service, which returns a JSON string. Problem is that the JSON is not an object but an array of objects, i.e.:
[
{ object_1 },
{ object_2 }
]
First, I want to figure out if this array is empty, as an expression in a choice-when statement:
.choice()
.when( <array-is-empty-expression> )
...
.otherwise()
...
As a solution I used an expression .when("${body} == '[ ]'") which works fine but it doesn't give me the flexibility to find out how many elements there are in the array (well, just that there are 0 or more than 0). So I would really like something like .when("${body expression} == 0").
Secondly, I want to have an expression that assigns a property of, for example, the second object from the JSON array, to set a header property. For example, .header("To", expression).
Can anyone help me with these expressions?
The best approach is to unmarshal your Json string to get a list of objects. Then you can invoke size() method to get the number of elements in your list. Finally, you can access any element of the list using [] operator:
from("file://C:/q69164959/test")
.unmarshal().json(JsonLibrary.Jackson)
.setHeader("To", simple("Default"))
.choice()
.when(simple("${body.size()} == 0" ))
.to("log:org.orzowei.so.question.q69164959?level=ERROR")
.otherwise()
.setHeader("To", simple("${body[0][a]}"))
.to("log:org.orzowei.so.question.q69164959?level=WARN")
.end()
.log(LoggingLevel.INFO, "header.To == ${header.To}")
Using [] as input, you can see this log output:
2021-09-13 23:41:49.830 ERROR 32028 --- [/q69076203/test] org.orzowei.so.question.q69164959 : Exchange[ExchangePattern: InOnly, BodyType: java.util.ArrayList, Body: ]
2021-09-13 23:41:49.830 INFO 32028 --- [/q69076203/test] route1 : header.To == Default
Using [{a=1, b=2}, {a=3, b=4}] as input, you can see this log output:
2021-09-13 23:42:01.161 WARN 32028 --- [/q69076203/test] org.orzowei.so.question.q69164959 : Exchange[ExchangePattern: InOnly, BodyType: java.util.ArrayList, Body: [{a=1, b=2}, {a=3, b=4}]]
2021-09-13 23:42:01.161 INFO 32028 --- [/q69076203/test] route1 : header.To == 1
Related
In Gatling (using Scala), I have extracted an array of value which I want to modify and use it in my subsequent request.
Post extraction, as part of modification, using .transform I tried replacing sub-string, but that doesn't work and throws an error 'not found: value transform'
Please see if you can look at the code below and suggest any fix.
1: foreach used to iterate through all array of value.
2: transform function is used to replace a substring with blank.
.exec(http("SC01_T03_Step2_Next")
.post("/function")
.headers(headers_9)
.check(
regex("[0-9]{2,3}</label></span></div>")
.findAll
.saveAs("c_LargeOrder"))
.formParam("utf8", "✓")
.formParam("authenticity_token", "#{c_AuthToken}")
.formParam("challenger[step_id]", "#{c_StepID2}")
.formParam("challenger[step_number]", "2")
.formParam("challenger[age]", "#{p_age}")
.formParam("commit", "Next")
.check(bodyString.saveAs("Trans3Body"))
)
.foreach("#{c_LargeOrder}", "c_LargeOrder1") // 1
{
exec(
session =>
{
transform(str => str.replace("</label></span></div>","")) // 2
}
)
}
I am trying to convert the below Array in to the JSON, trying by iterating through the Array and transforming. The array looks like below
Quote_Sent_To__r = [
{
Quote__c=0Q02D05XGQSA2,
Id=a1H2D0m94QUAQ,
type=QuoteSentTo__c
},
{
Quote__c=0Q02D00XGQSA2,
Id=a1H2D00000AQ,
type=QuoteSentTo__c
}
]
I have stored the array in to the variable quoteSentToList and iterating through the for loop
Within each iteration I need to get the JSON like
{
"Quote__c": "0Q02D05XGQSA2"
}
So this can be passed to the Salesforce Update operation. I tried like
%dw 2.0
output application/json
var item = vars.quoteSentToList[counter]
---
{
"Quote__c" :payload.Id
}
It errors saying
Reason: Unable to resolve reference of: counter..
Scripting language error on expression 'payload'. Reason: Unable to resolve reference of: payload..
This is my first project and any help is greatly appreciated
Error
""Unexpected character 'v' at quoteSentToList#[1:1] (line:column), expected false or true or null or {...} or [...] or number but was , while reading quoteSentToList as Json.
1| vars.existingQuote[0].Quote_Sent_To__r ^" evaluating expression: "%dw 2.0 output application/json
---
vars.quoteSentToList map { Quote__c: payload.Id, Id: $.Id }"."
counter is a Mule variable, not a DataWeave variable. You need to use the prefix vars. to reference it inside DataWeave scripts: vars.counter.
Alternatively, instead of using a <foreach> scope, you can transform the entire array at once and then use each element as needed:
%dw 2.0
output application/json
---
vars.quoteSentToList map { Quote__c: $.Id }
Output:
[
{
"Quote__c": "a1H2D0m94QUAQ"
},
{
"Quote__c": "a1H2D00000AQ"
}
]
Example:
API A:
{
"customer":[
{
"name":"Jane",
"phone":"9999999",
"email":"jane#test.com"
},
{
"name":"John",
"phone":"8888888",
"email":"john#test.com"
},
{
"name":"Joe",
"phone":"7777777",
"email":"Joe#test.com"
}
]
}
Using the JSON extractor, I want to get the names of all the customers
so: Jane, John, Joe
How do I get these values and turn them into an array
[{"name":"Jane", "name":"John", "name":"Joe"}]
And pass it onto the next API?
Note: That it has to be dynamic so API A could show different 2 names or 1 name or more and needs to be adjusted into the array
First of all your [{"name":"Jane", "name":"John", "name":"Joe"}] is not a valid JSON, you can check it yourself:
so I strongly doubt that this is the string you need to generate.
So if you really need to construct this value you can do something like:
Add JSR223 PostProcessor as a child of the request which returns this "customers" data
Put the following code into "Script" area:
def response = new groovy.json.JsonSlurper().parse(prev.getResponseData())
def payload = new StringBuilder()
payload.append('[{')
0.upto(response.customer.size - 1, { index ->
payload.append('"name": "').append(response.customer[index].name).append('"')
if (index != response.customer.size - 1) {
payload.append(',')
}
})
payload.append('}]')
vars.put('payload', payload as String)
Refer the generated value as ${payload} where required
Demo:
More information:
JsonSlurper
Apache Groovy - Parsing and producing JSON
Apache Groovy - Why and How You Should Use It
I have an issue. I am testing usage of the prefix(while:) and receive not expected result.Count of elements after prefix(while:) is missing one element. From the code it is possible to see that structures with name that has prefix Oleg are 5 but after prefix(while:) it returns 4.
Example :
struct User {
let name: String
}
let users = [User(name : "Oleg 1"),User(name : "Oleg 2"),User(name : "Oleg 3"),User(name : "Oleg 4"),User(name : "Igor 1"),User(name : "Oleg 5"),User(name : "Max 1")]
print(users.prefix { $0.name.hasPrefix("Oleg") }.count) //4
From the documentation for the Array prefix method:
Returns a subsequence containing the initial elements until predicate returns false and skipping the remaining elements.
When the code gets to the "Igor 1" instance, prefix stops and returns that first subrange giving the result of 4.
Don't confuse the Array prefix method and the String hasPrefix method. They are used for two completely different things.
Perhaps you want to use filter.
print(users.filter { $0.name.hasPrefix("Oleg") }.count) // 5
I am using json parser lib written in C to parse JSON objects. The lib link is : https://github.com/udp/json-parser.
The json object/string, which I am trying to parse is :
{"video_id": 105, "st": "S3", "processing" : [{"start" : "1", "end" : "2"}]}}
"processing" contains another JSON object.
I have parsed the first three items. But I am not able to figure out a way to parse the "processing" json object. I am using following code:-
if (!strcmp(json->u.object.values[i].name, "video_id"))
{
video_id=json->u.object.values[i].value->u.integer;
}
.
.
if (!strcmp(json->u.object.values[i].name, "processing"))
{
printf("\nNumber of JSON OBJECTS : %d\n", json->u.object.values[i].value->u.object.length);
}
json is the parsed object obtained via calling the lib on the JSON string. Can anyone guide me how to handle the nested object ?
Any help will be really appreciated
My complete code is :
json_value *json;
json_char *json_object="{\"video_id\": 105, \"st\": \"S3\", \"processing\" : [{\"type\" : \"clipping\"},{\"fese\" : \"dipping\"}]}";
printf("%s",json_object);
//json_value * json_parse (const json_char * json,
// size_t length);
json=json_parse(json_object, strlen(json_object));
// json_type json_object;
printf("\n%s\n",json->u.object.values[0].name);
printf("\t%d\n",json->u.object.values[0].value->u.integer);
printf("\n%s\n",json->u.object.values[2].name);
printf("\t%d\n",json->u.object.values[2].value->u.object.length);
printf("\t%s\n",json->u.object.values[2].value->u.object.values[0].name);
From the documentation, API field::
The type field of json_value is one of:
json_object (see u.object.length, u.object.values[x].name, u.object.values[x].value)
json_array (see u.array.length, u.array.values)
json_integer (see u.integer)
json_double (see u.dbl)
json_string (see u.string.ptr, u.string.length)
json_boolean (see u.boolean)
json_null
So, check the type field of the "processing" value. If found to be json_array, do a json_parse for the array to get a new json_value. Now this json_value will provide you with the nested JSON objects.
Take these as reference:
js_v->u.object.values[1].value->u.array.values[0]->type
js_v->u.object.values[1].value->u.array.values[0]->u.string.ptr
I've used them to reference to a string element inside an array:
{"t":"type","d":["element1","element2","element3"]}
In your case, I think you should to repeat the structure like this:
js_v->u.object.values[2].value->u.array.values[0]->u.object.values[0]->u.string.ptr
luck!