Parsing a JSON sub string - javascript

I have javascript function that calls an external Api and returns in most case a valid JSON string.
function (successResponse) {
{
console.log(successResponse);
}
However, in some cases it return the the following invalid JSON
Response: Status=200, Text: {"createdTime":"2017-05-08T14:47:56Z","lastUpdatedTime":"2017-05-08T14:47:56Z","createdMode":"API","uuid":"e333c1-3599-36d7-9ef5-dc22c79a4a52","userId":"anonymous"}, Error Message: null
How can I parse the above string to get the 'uuid'
Thanks

If you're expecting a response string in that format, you can use a regular expression to extract the "text" portion of the response:
function (successResponse) {
{
var responseText = successResponse.match(/\{.+\}/);
var responseTextJSON = JSON.parse(responseText);
var uuid = responseTextJSON.uuid;
console.log(uuid);
}

Maybe you can parse the string yourself to exclude everything outside of {} ?
var apiResponse = 'Response: Status=200, Text: {"createdTime":"2017-05-08T14:47:56Z","lastUpdatedTime":"2017-05-08T14:47:56Z","createdMode":"API","uuid":"e333c1-3599-36d7-9ef5-dc22c79a4a52","userId":"anonymous"}, Error Message: null';
var apiResponse_fixed = apiResponse.substring((apiResponse.indexOf("{") - 1), (apiResponse.lastIndexOf("}") + 1));
var json_obj = JSON.parse(apiResponse_fixed);
console.log(json_obj.uuid);

Replace the non-JSON features, and then interpret as JSON
Looks like the server owner has been a bit lazy, and programmed an error response which contains a JSON-like interior section but surrounded by a couple of non-JSON elements.
If you are desperate to resolve the situation and have no ability to fix the server output format, here is my suggestion:
notQuiteJson = 'Response: Status=200, Text: {"createdTime":"2017-05-08T14:47:56Z","lastUpdatedTime":"2017-05-08T14:47:56Z","createdMode":"API","uuid":"e333c1-3599-36d7-9ef5-dc22c79a4a52","userId":"anonymous"}, Error Message: null';
madeJson = notQuiteJson.replace('Response: Status=200, Text:','{"Response": {"Status":200}, "Text":').replace('Error Message: null','"ErrorMessage": null}')
obj = JSON.parse(madeJson)
console.log(obj.Text.uuid) // Result: "e333c1-3599-36d7-9ef5-dc22c79a4a52"
Of course this only works if the error message is always exactly this. In reality you may want to use a 3-digit wildcard to cover a range of "Status=" codes. But then you would have to also be confident that all the error modes produce the same non-JSON text at the start and end of the response.
Disclaimer
#sp00m and #Bergi, don't kill me: you are right of course, but this is just for if the poster has no choice in the matter 8-)

Related

Why is Google Scripts' JSON.parse method converting numbers to floats?

I'm writing a Google Script code to manage some data in Google Sheet. I'm pulling data from external API and every time I receive numbers in JSON response they're converted to floats by JSON.parse available in Google Script.
Example:
const test = '{ "numericValue": 0 }';
JSON.parse(test)
Result: {numericValue=0.0}
const test = '{ "stringValue": "0" }';
JSON.parse(test)
Result: {stringValue=0}
It doesn't happen with browser JSON.parse method.
Is there any way to fix this besides converting all numbers to strings before parsing?
The logger has always done that. But the console doesn't. Don't know the issue but you get use to it. Don't worry about it
function floatTest() {
const obj='{"value": 0 }';
console.log(JSON.parse(obj));
Logger.log(JSON.parse(obj));
}
Execution log
8:28:00 AM Notice Execution started
8:28:00 AM Info { value: 0 }
8:28:00 AM Info {value=0.0}
8:28:01 AM Notice Execution completed
a simple way to verify that what you are saying is wrong:
const test_1 = JSON.parse( '{ "val": 0 }')
console.log ('test_1', typeof test_1.val, Number.isInteger(test_1.val) , test_1.val )
const test_2 = JSON.parse( '{ "val": "0" }')
console.log ('test_2', typeof test_2.val, Number.isInteger(test_2.val) , test_2.val )

Convert string with '=' to JSON format

I am trying to convert a string i receive back from an API into a JSON object in Angular.
The issue is that the string is not normalized to be parsed into JSON easily.
This is the string im working with:
"{rootCause=EJBusinessException: This is a sample exception thrown for testing additional info field, description=This is a more detailed description about the incident., stackTrace=com.springboot.streams.infrastructure.web.heartbeat.HeartbeatService.testServiceNow(HeartbeatService.java:200)}"
When trying to do JSON.parse(myStr) it throws an error due to invalid string format.
Is there an easy way to convert the listed string into a more correct JSON format, getting rid of the '=' and replacing them with ':' instead.
There is more to it than just .replace(/['"]+/g, ''), as even with that the string is not ready to be turned into JSON yet.
Hoping someone more versed in Javascript knows a trick i dont.
You just need to manipulate the string before parsing it remove unecessary string that can cause error to the object like "{" and "}" and split it by "," example is in below.
var obj = {}, str = "{rootCause=EJBusinessException: This is a sample exception thrown for testing additional info field, description=This is a more detailed description about the incident., stackTrace=com.springboot.streams.infrastructure.web.heartbeat.HeartbeatService.testServiceNow(HeartbeatService.java:200)}"
str.split(",").forEach((st, i) => {
pair = st.split("=")
if(pair.length > 1) {
obj[pair[0].replace("{",'').replace("}", '').trim()] = pair[1]
} else {
obj[i] = pair
}
})
console.log(obj)
As commenters have posted, unless you control the API or at least have documentation that output will always follow a specific format, then you are limited in what you can do. With your current example, however you can trim off the extraneous bits to get the actual data... (remove braces, split on comma, split on equals) to get your key:value pairs... then build a javascript object from scratch with the data... if you need json string at that point can just JSON.stringify()
var initialString = "{rootCause=EJBusinessException: This is a sample exception thrown for testing additional info field, description=This is a more detailed description about the incident., stackTrace=com.springboot.streams.infrastructure.web.heartbeat.HeartbeatService.testServiceNow(HeartbeatService.java:200)}"
var trimmedString = initialString.substr(1, initialString.length - 2);
var pairArray = trimmedString.split(',');
var objArray = [];
pairArray.forEach(pair => {
var elementArray = pair.split('=');
var obj = {
key: elementArray[0].trim(),
value: elementArray[1].trim()
};
objArray.push(obj);
});
var returnObj = {};
objArray.forEach(element => {
returnObj[element.key] = element.value;
});
console.log(JSON.stringify(returnObj));

javascript - substitute into a string template, but catch missing variables

I want to carry out variable substitutions on a string (I've already ruled out template literals because the string has to be stored and evaluated later).
Mustache or something like it would seem like a contender, but I want to know if the substitution was incomplete. In this case, it's to produce urls, so missing parts mean invalid urls:
Testing this out in node:
var Mustache = require('mustache');
var result = Mustache.render("/someurl/{{path1}}/{{path2}}/", {path1:"my-path-to-1"})
console.log(`result:${result}:`)
This happens without a problem, but the resulting url is useless because Mustache silently replaced the missing path2 with an empty string. What I would like to see is an exception getting thrown (best) or failing that an easy way to recognize that not everything was substituted.
Note: the template string is arbitrary and so are the substitution object's contents.
output:
result:/someurl/my-path-to-1//:
This is the Python equivalent that I am looking for:
res = "/someurl/%(path1)s/%(path2)s/" % {"path1":"my-path-to-1"}
output:
KeyError: 'path2'
I ended up using sprintf, which has the benefit of having a different format than Mustache (or Django) so that you can embed it in data-url or the like:
const sprintf = require("sprintf-js").sprintf;
var o_substit = {
path1 : "mypath1"
};
var T_URL = "/someurl/%(path1)s/%(path2)s/";
console.log(`\nT_URL:${T_URL}, substitutions:`);
try {
console.dir(o_substit);
console.log("expecting a failure...")
var url = sprintf(T_URL, o_substit);
console.log(` url:${url}:`);
}
catch (e){
console.log(` exception:${e}`);
};
var o_substit = {
path1 : "mypath1"
,path2 : "mypath2"
};
console.log(`\nT_URL:${T_URL}, substitutions:`);
try{
console.dir(o_substit);
console.log("\nexpecting a success:")
var url = sprintf(T_URL, o_substit);
console.log(` url:${url}:`);
}
catch (e){
console.log(` exception:${e}`);
};
output:
T_URL:/someurl/%(path1)s/%(path2)s/, substitutions:
{ path1: 'mypath1' }
expecting a failure...
exception:Error: [sprintf] property 'path2' does not exist
T_URL:/someurl/%(path1)s/%(path2)s/, substitutions:
{ path1: 'mypath1', path2: 'mypath2' }
expecting a success:
url:/someurl/mypath1/mypath2/:

JSON Serialization error with simplejson

I have the following code:
data = {'services': [u'iTunes'],
'orders': [u'TestOrder', u'Test_April_Titles_iTunes'],
'providers': ''}
return HttpResponse(simplejson.dumps(data))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py" in default
178. raise TypeError(repr(o) + " is not JSON serializable")
Exception Type: TypeError at /reports/change_dropdown/
Exception Value: [u'iTunes'] is not JSON serializable
What do I need to do to serialize this dictionary with a list inside it?
The problem is that itunes is a non-JSON compatible type.
To solve provide default type to convert non-JSON compatible types when serializing:
simplejson.dumps(data, default=str))
or even:
def handler(val):
if isinstance(val, unicode)
return str(val)
else:
return val
simplejson.dumps(data, default=handler))
The advantage of the second option is you can handle sets (e.g., convert to list), dates (e.g., convert to int timetstamp), etc.
Converting from unicode to str worked here:
data['services'] = [str(item) for item in data['services']]
data['orders'] = [str(item) for item in data['orders']]
data['providers'] = [str(item) for item in data['providers']]

Firefox pref is destroying JSON

I have the following JSON: http://pastebin.com/Sh20StJY
SO removed the chars on my post, so look at the link for the real JSON
which was generated using JSON.stringify and saved on Firefox prefs (pref.setCharPref(prefName, value);)
The problem is that when I save the value, Firefox does something that corrupts the JSON. If I try a JSON.parse retrieving the value from the config I get an error:
Error: JSON.parse: bad control character in string literal
If I try to validate the above JSON (which was retrieved from the settings) I get an error at line 20, the tokens value contains two invalid characters.
If I try a JSON.parse immediately after JSON.stringify the error doesn't occur.
Do I have to set something to save in a different encoding? How can I fix it?
nsIPrefBranch.getCharPref() only works for ASCII data, your JSON data contains some non-ASCII characters however. You can store Unicode data in preferences, it is merely a little bit more complicated:
var str = Components.classes["#mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
str.data = value;
pref.setComplexValue(prefName, Components.interfaces.nsISupportsString, str);
And to read that preference:
var str = pref.getComplexValue(prefName, Components.interfaces.nsISupportsString);
var value = str.data;
For reference: Documentation
Your JSON appears to contain non-ASCII characters such as ½. Can you check what encoding everything is being handled in?
nsIPrefBranch.setCharPref() assumes that its input is UTF-8 encoded, and the return value of nsIPrefBranch.getCharPref() is always an UTF-8 string. If your input is a bytestring or a character in some other encoding, you will either need to switch to UTF-8, or encode and decode it yourself when interacting with preferences.
I did this in one place to fix this issue:
(function overrideJsonParse() {
if (!window.JSON || !window.JSON.parse) {
window.setTimeout(overrideJsonParse, 1);
return; //this code has executed before JSON2.js, try again in a moment
}
var oldParse = window.JSON.parse;
window.JSON.parse = function (s) {
var b = "", i, l = s.length, c;
for (i = 0; i < l; ++i) {
c = s[i];
if (c.charCodeAt(0) >= 32) { b += c; }
}
return oldParse(b);
};
}());
This works in IE8 (using json2 or whatever), IE9, Firefox and Chrome.
The code seems correct. Try use single quotes '..': '...' instead of double quotes "..":"..." .
I still couldn't find the solution, but I found a workaround:
var b = "";
[].forEach.call("{ JSON STRING }", function(c, i) {
if (c.charCodeAt(0) >= 32)
b += c;
});
Now b is the new JSON, and might work...

Categories

Resources