Parse ill formed JSON string - javascript

I am being sent an ill formed JSON string from a third party. I tried using JSON.parse(str) to parse it into a JavaScript object but it of course failed.
The reason being is that the keys are not strings:
{min: 100}
As opposed to valid JSON string (which parses just fine):
{"min": 100}
I need to accept the ill formed string for now. I imagine forgetting to properly quote keys is a common mistake. Is there a good way to change this to a valid JSON string so that I can parse it? For now I may have to parse character by character and try and form an object, which sounds awful.
Ideas?

You could just eval, but that would be bad security practice if you don't trust the source. Better solution would be to either modify the string manually to quote the keys or use a tool someone else has written that does this for you (check out https://github.com/daepark/JSOL written by daepark).

I did this just recently, using Uglifyjs to evaluate:
var jsp = require("uglify-js").parser;
var pro = require("uglify-js").uglify;
var orig_code = "var myobject = " + badJSONobject;
var ast = jsp.parse(orig_code); // parse code and get the initial AST
var final_code = pro.gen_code(ast); // regenerate code
$('head').append('<script>' + final_code + '; console.log(JSON.stringify(myobject));</script>');
This is really sloppy in a way, and has all the same problems as an eval() based solution, but if you just need to parse/reformat the data one time, then the above should get you a clean JSON copy of the JS object.

Depending on what else is in the JSON, you could simply do a string replace and replace '{' with '{"' and ':' with '":'.

Related

JSON.parse - How to handle capitalized Boolean values?

I am working on a Node.js application that needs to handle JSON strings and work with the objects.
Mostly all is well and JSON.parse(myString) is all I need.
The application also gets data from third parties. One of which seems to be developed with Python.
My application repeatable chokes on boolean values since they come captialized.
Example:
var jsonStr = "{'external_id': 123, 'description': 'Run #2944', 'test_ok': False}";
try{
var jsonObj = JSON.parse(jsonStr);
}catch(err){
console.err('Whoops! Could not parse, error: ' + err.message);
}
Notice the test_ok parameter - it all is good when it follows the Javascript way of having a lower case false boolean instead. But the capitalized boolean does not work out.
Of course I could try and replace capitalized boolean values via a string replace, but I am afraid to alter things that should not get altered.
Is there an alternative to JSON.parse that is a little more forgiving?
I don't mean to be rude but according to json.org, its an invalid json. That means you'll have to run a hack where you have to identify stringified boolean "True" and convert it to "true" without affecting a string that lets say is "True dat!"
First of all, I would not recommend using the code below. This is just to demonstrate how to convert your input string into a valid JSON. There were problems, one is the Boolean False, and another is the single quotes around property names. I'm not positive but I believe those need to be double quotes.
I don't believe having to convert a string into a valid JSON is a good choice. If you have no alternative, meaning you don't have access to the code generating this string, then the code below is still not a good choice because it will have issues if you have embedded quotes in the string values. i.e. you would need different string replace logic.
Keep all this in mind before using the code.
var jsonStr = "{'external_id': 123, 'description': 'Run #2944', 'test_ok': False}";
try {
jsonStr = jsonStr.replace(/:[ ]*False/,':false' ).replace( /'/g,'"');
var jsonObj = JSON.parse(jsonStr);
console.log( jsonObj );
} catch (err) {
console.err('Whoops! Could not parse, error: ' + err.message);
}

Converting a String into an Object

I'm receiving a string like obj{a="foo",b="bar",c=3,d=4.0} inside a nodejs environment I'm working in and I'm trying to convert this String into a reference-able Object like this:
{
a : "foo",
b : "bar",
c : 3,
d : 4.0
}
Assigned to obj of course.
I've used a myriad of formatting tricks but whenever I call JSON.parse() I get unexpected character errors. Usually on the first alpha-character it sees.
My next step is to write several nested loops to make all of the assignments manually but I'm hoping someone can point me in the right direction on how to parse this.
EDIT: Ok there's a little more to the story and I thought I should omit it but I guess explaining everything would be helpful.
The actual data packet that I'm receiving looks like this.
ack{a="000000061",b=0,c=2.0}\rb{a=244.0,b=255,c=4.0}\rc{a=6.0,b=55,c=55}endack;
So yeah that's the actual string I'm trying to parse into three distinct accessible Objects. I know I'm having a brain fart from a long day but yeah it's giving me a run for my money right now.
First replace the "=" with ":" and remove the obj infront
str = str.replace(/=/g, ":").replace("obj{", "{")
Since it's not in correct json format (but can be read by js parser) we can't use JSON.parse but we can use eval
eval("var obj = " + str);
Obvious there are some assumptions with this technique such that = always mean colon and you won't have obj{ as text (but the latter can be fixed with a simple substring method)
Keep in mind eval is also considered evil so use at your own risk. Imagine if the user were to send bad data, they could easily get into your parser and run something malicious. But hopefully this will give you an idea or inspiration to a better solution.
You can go a step further and use
str = 'obj{a="foo",b="bar",c=3,d=4.0}'
str = str.substr(3,str.length).replace(/([{,])([\w])=/g, '$1\"$2\":');
var obj = JSON.parse(str);

JSON from Newtonsoft to JavaScript

So, I have a some json data which I create in my controller like so:
Notes = JsonConvert.SerializeObject(contact.Notes.OrderBy(x => x.DateLogged).Select(x => new
{
id = x.Id,
date = x.DateLogged,
content = x.Content,
logged = x.Username
}))
This then gets passed to the view, now which statment can I do to achieve the results of having a variable contain that json data:
var data = '#Html.Raw(Model.Notes)'
or
var data = JSON.parse('#Html.Raw(Model.Notes)');
EDIT
the content variable holds some "\n" which when passed to the view using the first choice from above generates an error, saying
Unexpected Token
it only does it with \n so what is going wrong here? the bottom method doesn't quite work.
var data = JSON.parse('#Html.Raw(Model.Notes)');
This doesn't work - you can't put a JSON literal inside a JavaScript string. Any backslash in it will be an escape character to the JavaScript parser, not the JSON parser. A newline comes out like:
var data = JSON.parse('{"content": "abc\ndef"}');
which means the string you are asking JSON to parse is:
{"content": "abc
def"}
which is not valid as you can't have a literal newline in a JSON string.
To do this with JSON.parse you would have to JS-string-literal encode the JSON output, so you would end up with "abc\\ndef". The alternative would be to include the JSON directly in the script block as var data = #Html.Raw(Model.Notes);, but there are problems with this to do with the differences between JS and JSON (primarily characters U+2028 and U+2029) and the enclosing HTML context (ie what the sequence </script does).
Getting the escaping right here is harder than it looks, so you should avoid injecting anything into a <script> block. Better to put in-page JSON data in a data- attribute and read it from the DOM; this way you can use the normal HTML escaping Razor gives you by default.
<div id="notes" data-notes="#Model.Notes">
...
var data = JSON.parse(document.getElementById('notes').getAttribute('data-notes'));
bobince is obviously correct in what he says, it makes so much sense, thanks for that.
However, my solution was to simply do:
var data = #Html.Raw(Model.Notes);
Because, Newtonsoft already has converted it to a proper JSON format, so all it needs to do, is be assigned to a variable to be manipulated.
I think grabbing the content from a the HTML DOM is a bit too much for this.

How decode HEX in XMLHtppRequest?

I have a site and I used AJAX. And I got some problems.
Server return JSON string something like this {a:"x48\x65\x6C\x6C\x6F"}.
Then in xx.responseText, we have this string '{a:"\x48\x65\x6C\x6C\x6F"}'.
But if I create JavaScript string "\x48\x65\x6C\x6C\x6F" then I have "Hello" and not HEX!
Is it possible get in xx.responseText "real" text from HEX (automatically, without .replace())?
If the output is at all regular (predictable), .replace() is probably the simplest.
var escapeSequences = xx.responseText.replace(/^\{a:/, '').replace(/\}$/, '');
console.log(escapeSequences === "\"\\x48\\x65\\x6C\\x6C\\x6F\""); // true
Or, if a string literal that's equivalent in value but may not otherwise be the same is sufficient, you could parse (see below) and then stringify() an individual property.
console.log(JSON.stringify(data.a) === "\"Hello\""); // true
Otherwise, you'll likely need to run responseText through a lexer to tokenize it and retrieve the literal from that. JavaScript doesn't include an option for this separate from parsing/evaluating, so you'll need to find a library for this.
"Lexer written in JavaScript?" may be a good place to start for that.
To parse it:
Since it appears to be a string of code, you'll likely have to use eval().
var data = eval('(' + xx.responseText + ')');
console.log(data.a); // Hello
Note: The parenthesis make sure {...} is evaluated as an Object literal rather than as a block.
Also, I'd suggest looking into alternatives to code for communicating data like this.
A common option is JSON, which takes its syntax from JavaScript, but uses a rather strict subset. It doesn't allow functions or other potentially problematic code to be included.
var data = JSON.parse(xx.responseText);
console.log(data.a); // Hello
Visiting JSON.org, you should be able to find a reference or library for the choice of server-side language to output JSON.
{ "a": "Hello" }
Why not just let the JSON parser do its job and handle the \x escape sequences, and then just convert the string back to hex again afterwards, e.g.
function charToHex(c) {
var hex = c.charCodeAt(0).toString(16);
return (hex.length === 2) ? hex : '0' + hex;
}
"Hello".replace(/./g, charToHex); // gives "48656c6c6f"

Extracting values with Javascript

I have a variable called "result",
var result;
that result value is equal to following value, please presume that is just a string :)
---------result value -----------
for (;;);{
"send":1,
"payload":{
"config":{
"website":"",
"title":"welcome to site",
"website-module":1313508674538,
"manufatureid":"id.249530475080015",
"tableid":"id.272772962740259",
"adminid":100002741928612,
"offline":null,
"adminemail":"admin#website.com",
"adminame":"George",
"tags":"web:design:template",
"source":"source:design:web",
"sitelog":[],
"errorlog":0,
"RespondActionlog":0,
"map":null
},
"imgupload":""
},
"criticalerror":[0],
"report":true
}
---------result value------------
From that value, I would like to extract tableid which is "id.272772962740259" with classic Javascript.
How can I extract the code, please let me know how can i do with simple javascript, please don't use Jquery, all I just need is simple javascript.
You can simply evaluate the value of the variable to obtain the values. However, please note that your current value is not valid JSON; that for(;;); at the beginning of the value invalidates the format. Remove that, and you can do this:
var object = eval('(' + resultMinusThatForLoop + ')');
alert(object.payload.config.tableid);
If that data is a string the parse it with a JSON parse. The following should get the value you want
JSON.parse(result).payload.config.tableid; // "id.272772962740259"
Edit: though, as Tejs says, the for(;;) invalidates the string and stops it from being parsed. If you can remove that, do.
You need to remove the empty for loop, then parse the string. DO NOT use eval; most modern browsers provide built-in JSON-parsing facilities, but you can use json2.js if yours does not. Assuming that you assign the results of parsing the JSON to result, you should be able to get that value using result.payload.config.tableid.
You should probably read a good JS reference. JavaScript: The Good Parts or Eloquent JavaScript would be a good choice.
If result is a javascript object and not a string, you can just use 'result.payload.config.tableid'.
If it is not, how do you get the AJAX result? Are you using XmlHttpRequest directly? Most libraries will give you a javascript object, you might be missing a flag or not sending the response back with the right content type.
If it is a string and you want to parse it manually, you should use a JSON parser. Newer browsers have one built in as window.JSON, but there is open source code for parsing it as well.
var obj = JSON.parse(result);
alert('tableid is ' + obj.payload.config.tableid);

Categories