Kettle PDI - Modified JavaScript - Json function not available - json

I'm using Kettle PDI 6.0 running on Windows Server 2012. I need to use the Modified Java Script Value to handle on Json object. I try something like this:
var jsondata = JSON.parse(result);
And get that:
"TypeError: Cannot find function parse in object test value test value test value test value test value test value test value test value test value test value. (script#3)"
I already try to looking for a solution on google, but not looks like that. I think that can be something wrong with my installation.
Note: I already try to use the command:
import java.util.*;
But that command is not recognized (Is not marked in bold).
I get:
missing ; before statement (script#2)
Maybe the Java functions not available.

I made my own function to resolve the problem. I will post here to help who has the same problem. If anyone want to help to solve the initial problem, I am still interested.
You can paste the code bellow on your "Modified Java Script Value" step after receive the Json response from service or get that on file. Note that you need to change the name of variables that you want to find on Json.
Result field is a Json Value.
//Script here
function findInArray(myValue, myArray){
var myResult='';
if(myArray.indexOf(myValue) > -1){
myResult = true;
} else {
myResult = false;
}
return myResult;
}
function getAttributeValue(Atribute, Object)
{
start = indexOf(Object,Atribute);
for (i= start; i < Object.length; i++)
{
if (substr(Object,i,1) == ":")
{
start_value = i+1;
break;
}
}
for (i= start_value; i < Object.length; i++)
{
end_value = i;
if (substr(Object,i,1) == ",")
{
break;
}
}
AttributeValue = replace(substr(Object, start_value, end_value-start_value),'"','');
if (indexOf(AttributeValue, "null") >= 0)
{
AttributeValue = null;
}
return AttributeValue ;
}
// Recupera Status
if (findInArray("status",result))
{
var status = getAttributeValue("status", result);
}
else
{
var status = "";
}
// Recupera _ID
if (findInArray("_id",result))
{
var mandrill_id = getAttributeValue("_id", result);
}
else
{
var mandrill_id = "";
}
// Recupera reject_reason
if (findInArray("reject_reason",result))
{
var reject_reason = replace(getAttributeValue("reject_reason", result),"}","");
}
else
{
var reject_reason = "";
}

yes, the parse json function is not available on the ex4 ecmascript of js rhino engine build in kettle, but you can handle json in kettle using eval.
var resultObj = eval('('+result+')');
//now you can iterate the foo elements of result original json
for(i=0;i< resultObj.length;i++){
Alert('foo number ' + i ' value = ' + resultObj[i].foo);
}
This is not javascript for the browser so eval is perfectly safe.

Related

Send unassigned JSON properties to server when using stringify i.e. retain properties name whether property value is empty/null

I have two model properties:
ng-model="category.name" mandatory field
ng-model="category.desc" optional
This is how I am sending data to the server (ASP.net)
var rdt = "{'dt':" + JSON.stringify($scope.category) + "}";
However, if an optional property has an unassigned value, the property name is not found server side and gives an error. Are there any ways to retain unassigned properties of JSON?
You have several solutions:
Solution 1: Initialize the variables in your scope for example:
$scope.category.desc = null
Solution 2: Create a function to take care of that
function ToJson(object, properties) {
var result = {};
for(var i = 0; i < properties.lenght; i++) {
var property = properties[i];
if(!object[property]) {
result[property] = null;
} else {
result[property] = object[property];
}
}
return JSON.stringify(result);
}
// And then use it like this:
var rdt = "{'dt':" + ToJson($scope.category, ["name", "desc"]) + "}";

Using FiddlerScript (JScript.Net) to change JSON response to null

I am using Fiddler's "FiddlerScript" to modify responses from a web server so that I can test responses in my app.
Here is my OnBeforeResponse function:
static function OnBeforeResponse(oSession: Session) {
// This code was already here, leaving it
if (m_Hide304s && oSession.responseCode == 304) {
oSession["ui-hide"] = "true";
}
// Here is new code to modify server's response
if(oSession.HostnameIs("mydomain.com") && oSession.uriContains("config")) {
// Color this response, so we can spot it in Fiddler
oSession["ui-backcolor"] = "lime";
// Convert the request body into a string
var oBody = System.Text.Encoding.UTF8.GetString(oSession.responseBodyBytes);
var j: Fiddler.WebFormats.JSON.JSONParseResult;
// Convert the text into a JSON object
// In this case our JSON root element is a dictionary (HashTable)
j = Fiddler.WebFormats.JSON.JsonDecode(oBody);
// Inside of our dictionary, we have an array (ArrayList) called "placements"
var testObject = j.JSONObject["test"];
/* Change this to different values, e.g. "0.0", 0.0, null, "", etc. */
/* This works */
testObject["consent_version"] = "";
/* This works */
testObject["consent_version"] = 0.0;
/* This works */
testObject["consent_version"] = "0.0";
/* This fails */
testObject["consent_version"] = null;
// Convert back to a byte array
var modBytes = Fiddler.WebFormats.JSON.JsonEncode(j.JSONObject);
// Convert json to bytes, storing the bytes in request body
var mod = System.Text.Encoding.UTF8.GetBytes(modBytes);
oSession.ResponseBody = mod;
}
}
I am able to set testObject["consent_version"] to any value except null. If I set this to null, Fiddler creates JSON which doesn't have any value, and the JSON is in a bad format like this:
"consent_version":,
Note that there is no value after "consent_version" and before the comma.
Does anyone know how I can use FiddlerScript (which is based on JScript.Net) to set a null value?
I know this is an old question, but I came across it trying to do the exact same thing, and finally figured it out... Hopefully this helps someone in the future.
First off, instead of setting it to null, set it to undefined. Chrome developer tools still shows it as returning as null.
Then, instead of
var modBytes = Fiddler.WebFormats.JSON.JsonEncode(j.JSONObject);
var mod = System.Text.Encoding.UTF8.GetBytes(modBytes);
oSession.ResponseBody = mod;
Use:
var modBytes = Fiddler.WebFormats.JSON.JsonEncode(j.JSONObject);
oSession.utilSetResponseBody(modBytes);
And you should be all set.
Here's a full example:
static function OnBeforeResponse(oSession: Session) {
if (m_Hide304s && oSession.responseCode == 304) {
oSession["ui-hide"] = "true";
}
if (true && (oSession.host=="domain.com") && (oSession.PathAndQuery.indexOf("/GetDataFromServer")>-1) && (oSession.oResponse.headers.ExistsAndContains("Content-Type", "json")) ){
oSession["ui-bold"]="true";
// Convert the request body into a string
oSession.utilDecodeResponse();
var oBody = System.Text.Encoding.UTF8.GetString(oSession.responseBodyBytes);
// FiddlerObject.log(oBody);
var j: Fiddler.WebFormats.JSON.JSONParseResult;
j = Fiddler.WebFormats.JSON.JsonDecode(oBody);
// FiddlerObject.log(j.JSONObject[0]["PropertyName"]);
j.JSONObject[0]["PropertyName"] = undefined;
// Convert back to a byte array
var modBytes = Fiddler.WebFormats.JSON.JsonEncode(j.JSONObject);
oSession.utilSetResponseBody(modBytes);
}
}

Understanding ES6 tagged template literal

Following code snippet is used on Mozilla (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) to explain Tagged Template literal, please help me understand what following function is doing, i am unable to get the actual flow of the function, since they have used keys.foreach and when i inspected in Chrome, keys was a function, so not able to understand
function template(strings, ...keys) {
return (function(...values) {
var dict = values[values.length - 1] || {};
var result = [strings[0]];
keys.forEach(function(key, i) {
var value = Number.isInteger(key) ? values[key] : dict[key];
result.push(value, strings[i + 1]);
});
return result.join('');
});
}
var t1Closure = template`${0}${1}${0}!`;
t1Closure('Y', 'A'); // "YAY!"
var t2Closure = template`${0} ${'foo'}!`;
t2Closure('Hello', {foo: 'World'}); // "Hello World!"
Most of the complexity in the example comes from the overloaded function and the forEach invocation, not from the tagged template literals. It might better have been written as two separate cases:
function dictionaryTemplate(strings, ...keys) {
return function(dict) {
var result = "";
for (var i=0; i<keys.length; i++)
result += strings[i] + dict[keys[i]];
result += strings[i];
return result;
};
}
const t = dictionaryTemplate`${0} ${'foo'}!`;
t({0: 'Hello', foo: 'World'}); // "Hello World!"
function argumentsTemplate(strings, ...keys) {
is (!keys.every(Number.isInteger))
throw new RangeError("The keys must be integers");
return function(...values) {
var result = "";
for (var i=0; i<keys.length; i++)
result += strings[i] + values[keys[i]];
result += strings[i];
return result;
};
}
const t = argumentsTemplate`${0}${1}${0}!`;
t('Y', 'A'); // "YAY!"
Template is a custom function defined by us to parse the template string, whenever a function is used to parse the template stringThe first argument of a tag function contains an array of string values. The remaining arguments are related to the expressions. so here specifically we have written the function to that given output I had got confused because when in inspected keys inside the forEach, i got a function in console, but inspecting the function before forEach gave keys as the array of configurable string ${0} and ${1} in first example

How to parse unstructured JSON file in Node?

I have to parse a JSON file that has many objects but no structure to the file. It looks like this:
{"obj1": "john"}
{"obj2": "sally"}
{"obj3": "veronica"}
Each object is on on it's own there is no container. So when I open the file and try to iterate through it I get the error Unexpected token { in JSON
Aside from wrapping the objects in an array and then manually going through the whole file to add commas, how can I parse this?
If it's really one-object-per-line, it's fairly straightforward to take the string, break it into lines, and JSON.parse each line:
const str =
'{"obj1": "john"}\n' +
'{"obj2": "sally"}\n' +
'{"obj3": "veronica"}';
const array = str.split(/[\r\n]+/)
.map(entry => JSON.parse(entry));
console.log(array);
...but that's assuming it really is one object per line.
If you're reading the file, you don't have to start out with all in one string as above; just read line by line as Kevin B points out.
(Since you're using Node, I've happily used ES2015+ features above...)
If you assume each line of the input file is complete, self-standing JSON, then a split-into-lines-then-parse-each strategy works well.
But even if the data isn't limited to a single line, not all is lost. You can heuristically parse the file. It isn't hyper-efficient, but except for very large files you'll probably never know the difference:
function incrementallyParseJSON(filepath) {
var lines = fs.readFileSync(filepath)
.toString()
.split(/\n/g);
var result = [];
var [start, stop] = [0, 1];
while (stop <= lines.length) {
try {
var part = JSON.parse(lines.slice(start, stop).join('\n'));
result.push(part);
[start, stop] = [stop, stop+1];
} catch (e) {
stop += 1;
}
}
return result;
}
So if your file is:
{"obj1": "john"}
{"obj2": "sally",
"more": "other"}
{"obj3": "veronica"}
"something"
12
The result will be:
[ { obj1: 'john' },
{ obj2: 'sally', more: 'other' },
{ obj3: 'veronica' },
'something',
12 ]
Example:
function incrementallyParseJSON(str) {
var lines = str.split(/\n/g);
var result = [];
var [start, stop] = [0, 1];
while (stop <= lines.length) {
try {
var part = JSON.parse(lines.slice(start, stop).join('\n'));
result.push(part);
[start, stop] = [stop, stop+1];
} catch (e) {
stop += 1;
}
}
return result;
}
var str =
'{"obj1": "john"}\n' +
'{"obj2": "sally",\n' +
' "more": "other"}\n' +
'{"obj3": "veronica"}\n' +
'"something"\n' +
'12';
console.log(incrementallyParseJSON(str));

GoogleScript Spreadsheet Custom Function Handling a range of cells and getting their values

I have a Goggle Spreadsheet with some data, and I want to write a custom function to use in the sheet, which accepts a range of cells and a delimiter character, takes each cell value, splits it by the delimiter, and counts the total.
For example
Column A has the following values in rows 1-3: {"Sheep","Sheep,Dog","Cat"}
My function would be called like this: =CountDelimitedValues(A1:A3;",");
It should return the value: 4 (1+2+1)
The problem I am having is in my custom script I get errors like
"TypeError: cannot get function GetValues from type Sheep"
This is my current script:
function CountArrayList(arrayList, delimiter) {
var count = 0;
//for (i=0; i<array.length; i++)
//{
//count += array[i].split(delimiter).length;
//}
var newArray = arrayList.GetValues();
return newArray.ToString();
//return count;
}
I understand that the parameter arraylist is receiving an array of objects from the spreadsheet, however I don't know how to get the value out of those objects, or perhaps cast them into strings.
Alternatively I might be going about this in the wrong way? I have another script which extracts the text from a cell between two characters which works fine for a single cell. What is it about a range of cells that is different?
That's something you can achieve without using script but plain old formula's:
=SUM(ARRAYFORMULA(LEN(A1:A3)-LEN(SUBSTITUTE(A1:A3; ","; "")) + 1))
Credit goes here: https://webapps.stackexchange.com/q/37744/29140
something like this works :
function CountArrayList(arrayList) {
return arrayList.toString().split(',').length
}
wouldn't it be sufficient ?
edit Oooops, sorry I forgot the user defined delimiter, so like this
function CountArrayList(arrayList,del) {
return arrayList.toString().split(del).length
}
usage : =CountArrayList(A1:C1;",")
NOTE : in this example above it would be dangerous to use another delimiter than "," since the toString() joins the array elements with commas... if you really need to do so try using a regex to change the commas to what you use and apply the split on that.
try like this :
function CountArrayList(arrayList,del) {
return arrayList.toString().replace(/,/g,del).split(del).length
}
Another solution I have was that I needed to implicitly cast the objects in the array being passed as a string.
For example this function accepts the array of cells, and outputs their contents as a string with del as the delimiter (similar to the String.Split() function). Note the TrimString function and that it is being passed an element of the array.
function ArrayToString(array,del) {
var string = "";
for (i=0; i < array.length; i++) {
if (array[i] != null) {
var trimmedString = TrimString(array[i]);
if (trimmedString != "") {
if (string.length > 0) {
string += del;
}
string += trimmedString;
}
}
}
return string;
}
Below is the TrimString function.
function TrimString(string) {
var value = "";
if (string != "" && string != null) {
var newString = "";
newString += string;
var frontStringTrimmed = newString.replace(/^\s*/,"");
var backStringTrimmed = frontStringTrimmed.replace(/\s*$/,"");
value = backStringTrimmed;
}
return value;
}
What I found is that this code threw a TypeError unless I included the declaration of the newString variable, and added the array element object to it, implicitly casting the array element object as a string. Otherwise the replace() functions could not be called.