JSON.parse invalid character with valid JSON? - javascript
So, I have an object whose properties also contain json strings within them. When serializing this object, this is the string I get:
[{
"template": 1,
"action_json": "{\"id\":\"1\",\"action\":\"An action for all of IT!\",\"date_agreed\":\"2018-08-10\",\"complete_by\":\"2018-08-31\",\"responsible_departments\":[\"8\"],\"responsible_employees\":[\"1629\",\"112\",\"1374\"],\"priority\":\"High\"}",
"template_json": "{\"columns\":[{\"id\":\"id\",\"title\":\"Task Number\",\"default\":true,\"type\":\"auto\"},{\"id\":\"action\",\"title\":\"Action Agreed\",\"default\":true,\"type\":\"longtext\"},{\"id\":\"date_agreed\",\"title\":\"Date Agreed\",\"default\":true,\"type\":\"date\"},{\"id\":\"complete_by\",\"title\":\"Complete By\",\"default\":true,\"type\":\"date\"},{\"id\":\"responsible_departments\",\"title\":\"Responsible Departments\",\"default\":true,\"type\":\"option\"},{\"id\":\"responsible_employees\",\"title\":\"Responsible Employees\",\"default\":true,\"type\":\"option\"},{\"id\":\"priority\",\"title\":\"Priority\",\"default\":true,\"type\":\"option\",\"options\":[\"High\",\"Medium\",\"Low\"]}]}"
}, {
"template": 1,
"action_json": "{\"id\":\"1\",\"action\":\"Action numero uno\",\"date_agreed\":\"2018-08-10\",\"complete_by\":\"2018-08-10\",\"responsible_departments\":[\"8\"],\"responsible_employees\":[\"112\"],\"priority\":\"High\"}",
"template_json": "{\"columns\":[{\"id\":\"id\",\"title\":\"Task Number\",\"default\":true,\"type\":\"auto\"},{\"id\":\"action\",\"title\":\"Action Agreed\",\"default\":true,\"type\":\"longtext\"},{\"id\":\"date_agreed\",\"title\":\"Date Agreed\",\"default\":true,\"type\":\"date\"},{\"id\":\"complete_by\",\"title\":\"Complete By\",\"default\":true,\"type\":\"date\"},{\"id\":\"responsible_departments\",\"title\":\"Responsible Departments\",\"default\":true,\"type\":\"option\"},{\"id\":\"responsible_employees\",\"title\":\"Responsible Employees\",\"default\":true,\"type\":\"option\"},{\"id\":\"priority\",\"title\":\"Priority\",\"default\":true,\"type\":\"option\",\"options\":[\"High\",\"Medium\",\"Low\"]}]}"
}]
Which is fine, this is valid JSON.
The problem arises when I try to create a JavaScript object by parsing this string (using PHP):
echo "<script>
var employeeActions = JSON.parse('".json_encode($employeeActions)."');
</script>";
And then I get:
JSON.parse Error: Invalid character at position:33
When inspecting the page once it's loaded, here is what is echoed through my PHP script:
<script>
var employeeActions = JSON.parse('[{"template":1,"action_json":"{\"id\":\"1\",\"action\":\"An action for all of IT!\",\"date_agreed\":\"2018-08-10\",\"complete_by\":\"2018-08-31\",\"responsible_departments\":[\"8\"],\"responsible_employees\":[\"1629\",\"112\",\"1374\"],\"priority\":\"High\"}","template_json":"{\"columns\":[{\"id\":\"id\",\"title\":\"Task Number\",\"default\":true,\"type\":\"auto\"},{\"id\":\"action\",\"title\":\"Action Agreed\",\"default\":true,\"type\":\"longtext\"},{\"id\":\"date_agreed\",\"title\":\"Date Agreed\",\"default\":true,\"type\":\"date\"},{\"id\":\"complete_by\",\"title\":\"Complete By\",\"default\":true,\"type\":\"date\"},{\"id\":\"responsible_departments\",\"title\":\"Responsible Departments\",\"default\":true,\"type\":\"option\"},{\"id\":\"responsible_employees\",\"title\":\"Responsible Employees\",\"default\":true,\"type\":\"option\"},{\"id\":\"priority\",\"title\":\"Priority\",\"default\":true,\"type\":\"option\",\"options\":[\"High\",\"Medium\",\"Low\"]}]}"},{"template":1,"action_json":"{\"id\":\"1\",\"action\":\"Action numero uno\",\"date_agreed\":\"2018-08-10\",\"complete_by\":\"2018-08-10\",\"responsible_departments\":[\"8\"],\"responsible_employees\":[\"112\"],\"priority\":\"High\"}","template_json":"{\"columns\":[{\"id\":\"id\",\"title\":\"Task Number\",\"default\":true,\"type\":\"auto\"},{\"id\":\"action\",\"title\":\"Action Agreed\",\"default\":true,\"type\":\"longtext\"},{\"id\":\"date_agreed\",\"title\":\"Date Agreed\",\"default\":true,\"type\":\"date\"},{\"id\":\"complete_by\",\"title\":\"Complete By\",\"default\":true,\"type\":\"date\"},{\"id\":\"responsible_departments\",\"title\":\"Responsible Departments\",\"default\":true,\"type\":\"option\"},{\"id\":\"responsible_employees\",\"title\":\"Responsible Employees\",\"default\":true,\"type\":\"option\"},{\"id\":\"priority\",\"title\":\"Priority\",\"default\":true,\"type\":\"option\",\"options\":[\"High\",\"Medium\",\"Low\"]}]}"}]');
</script>
The text you output from json_encode will be passed through the parser for JavaScript string literals before it gets passed through JSON.parse.
Since JSON and JS string literals use the same escape characters, this will break it! You are mashing up ' characters and data to try to construct a JS string literal programmatically, but the data includes characters with special meaning in JS.
"{\"i
That shows character 33. The JS string literal \" will be parsed putting an unescaped " in the string.
Forget about using JSON.parse. Forget about trying to pass JSON to the browser. Remember that JSON and JavaScript literal syntax are more or less the same thing:
<script>
var employeeActions = <?php echo json_encode($employeeActions); ?>;
</script>
Related
JSON.parse failing
I'm trying to create a JavaScript object from a JSON string "object" but it fails with the error: "SyntaxError: JSON.parse: expected ',' or '}' after property value in object at line 1 column 48 of the JSON data" var jsobj = JSON.parse( '{"lineID":11,"siteID":3,"mystring":"this is a \"Test\" string with quotes"}' ); mystring is a string which includes double quotes but I've escaped them correctly with the backslash. Why would it fail? I noticed it passes OK on this online JSON parsing site: json parser
The \ character is an escape character for JavaScript and JSON. When the JavaScript parser parses the string literal it turns \" in the JavaScript source code into " in the string. When the JSON parser parses the string, it finds an unescaped " and errors. To include \" in the JSON data, you need to escape the \ in the JavaScript string literal: \\". var jsobj = JSON.parse('{"lineID":11,"siteID":3,"mystring":"this is a \\"Test\\" string with quotes"}'); console.log(jsobj); Nesting data formats is always a pain. It is best to avoid doing that whenever possible. It doesn't make sense to have a string literal containing JSON in JavaScript in the first place. JSON is a subset of JavaScript. Just use the JSON as a JavaScript literal. var jsobj = { "lineID": 11, "siteID": 3, "mystring": "this is a \"Test\" string with quotes" }; console.log(jsobj);
For double quotes you have to use double backslash var jsobj = JSON.parse( '{"lineID":11,"siteID":3,"mystring":"this is a \\"Test\\" string with quotes"}' ); this should work
How do JSON.parse() and escape characters work in JavaScript?
Suppose I have an object variable: var obj = { key: '\"Hello World\"' } Then I tried parse it to string by using JSON.stringify in Chrome devtools console: JSON.stringify(obj) // "{"key":"\"Hello World\""}" I get the result "{"key":"\"Hello World\""}". Then I give it to a string var str = '{"key":"\"Hello World\""}' At least I try to convert it back to obj: JSON.parse(str); but the browser tell me wrong Uncaught SyntaxError What confused me is why this is wrong? I get the string from an origin object and I just want turn it back. How can I fix this problem? If I want do the job like convert obj to string and return it back, how can I do?
You're tried to convert your JSON into a string literal by wrapping it in ' characters, but \ characters have special meaning inside JavaScript string literals and \" gets converted to " by the JavaScript parser before it reaches the JSON parser. You need to escape the \ characters too. var str = '{"key":"\\"Hello World\\""}' That said, in general, it is better to not try to embed JSON in JavaScript string literals only to parse them with JSON.parse in the first place. JSON syntax is a subset of JavaScript so you can use it directly. var result = {"key":"\"Hello World\""};
try: var str = '{"key":"\\"Hello World\\""}';
Remove Backslash Escaping in Javascript Array
I have a pretty complex problem. I'm using PHP to parse a CSV file to an array and then var array = <?php echo json_encode( $array ) ?>; to pass it to the Javascript array. array is 2-dimensional, like so: var array = [["\/\\ssa","14104","26","2113","0","867","28083","15","43695"], ["Yee","8661","24","2215","0","991","25245","15","49086"],...] Now sometimes there seems to be a problem with backslash escapes in the username when it is structured like this: ["username\","sth","sth",...], so when the username ends with a backslash \ . The output will be: username", sth, sth, ... But this is only the first element of the sub-array, the other 8 places are empty. I have already tried to fix it with a loop replace, but I don't know how to add \" as search value. Is this impossible to do in JS since \" always escapes? Already tried charAt() to compare the last character with the backslash, but no success. Do I have to replace it before passing it to JS, in PHP? The Parse function is this, if it's important: <?php> $url = "data.csv"; $csvData = file_get_contents($url); $lines = explode(PHP_EOL, $csvData); $array = array(); foreach ($lines as $line) { $array[] = str_getcsv($line); ?> Here a JSfiddle you can play with: https://jsfiddle.net/cLmbe0qf/
You just need to replace backslashes by an html special character : foreach ($lines as $line) { $line = str_replace("\\", "\", $line); // ... }
This is a little bit more tricky since you have to parse the javascript into an object/array. Anytime you do this, the backslash is parsed out. To avoid doing this you need to store the value in the HTML page or use String.raw to get the literal version of the string. One way to implement it is to put the the string in the html and get the value of a hidden textarea. (you could store it anywhere, i just chose textarea). You then pass it through this javascript function slashParse which will replace all slashes with ~{}~ then run the javascript parsing algorithm, then replace the ~{}~ back to the backslashes. function slashParse(target) { var value = document.getElementById(target).value; var replacedVal = value.replace(/\\/g, '~{}~'); var parsedVal = JSON.parse(replacedVal); var mappedVal = parsedVal.map(function(item) { return item.replace(/~{}~/g, '\\'); }); return mappedVal; } var parsed = slashParse('input'); console.log(parsed) document.getElementById("test").innerText = parsed; <body> <div id="test"></div> </body> <textarea style="display:none" id="input">["use\rna</textarea><textarea>me\\","2","3","4"]</textarea> What echoing it out onto the page might look like would be like this. <textarea style="display:none" id="php-part"> <?=json_encode(htmlentities($array,ENT_NOQUOTES))?> </textarea> This is only one solution of a few more. Another option is to do more parsing on the php side of things. The problem you will run into, is that at some point you need to run the string through the JavaScript parsing program. When that happens you cannot have any backslashes. Then after you run it through the parsing, you will have to convert all hidden backslashes back to backslashes. The one problem with this method is that if there is anywhere EVER where ~{}~ is being placed in the string, it will be converted to backslashes afterwards. Something you can do in order to make it more aloof is to make the string backslashes get turn into even more obfuscated. Such as ~{BACKSLASH_ESCAPE}~
How to parse HTML string using JSON.parse() in JavaScript?
I have an ASP.NET MVC application returning a JSON string to the VIEW. // Parsing the model returned on the VIEW var jsonString = '#Html.Raw(Model.ToJson())'; var jsonObj = JSON.parse(jsonString); The problem is that I am not able to parse because the jsonString contains characters such as "\" and "'". //Sample string { "description" : "<p>Sample<span style=\"color: #ff6600;\"> Text</span></strong></p>" }
JSON is valid JavaScript, so you can just do this: var jsonObj = #Html.Raw(Model.ToJson()); FYI, the reason the JSON parsing is failing is because the although the " are escaped with \ to make it valid JSON, the backslashes themselves need escaping in the string for them to be seen by the JSON parser. Compare: JSON.parse('"quote: \""'); // error: unexpected string JSON.parse('"quote: \\""'); // 'quote: "' This example should also clarify what's happening to the backslashes: var unescaped = '\"', escaped = '\\"'; console.log(unescaped, unescaped.length); // '"', 1 console.log(escaped, escaped.length); // '\"', 2
If you want to create a valid Javascript string, you need to escape backslashes and apostrophes: var jsonString = '#Html.Raw(Model.ToJson().Replace("\\", "\\\\").Replace("'", "\\'"))';
There you go: using Newtonsoft.Json; JsonConvert.SerializeObject(your html string here);
JSON.stringify / parse oddness with quote marks
I am running into an odd little problem with parsing some JSON which has quotes in it. I am using the native JSON.stringify and JSON.parse functions to do this. If I stringify an object which an object which has quote marks in it, they are escaped as one would expect. If I then parse this back into an object, it again works fine. The problem is occurring where I stringify, then print the object to a page, then parse the resulting string. If I try to do this, the parse function fails as stringify has only put single slashes before each of the offending quote marks. The reason I need to achieve this is I am working on an application that dynamically loads content stored in a database as JSON strings. The strings at some point need to be printed onto the page somewhere so that the javascript can find them and build the page based on their contents. I need some way of robustly passing the object into and out of strings which will not fail if a user inputs the wrong characters! I can solve this for the moment by inserting extra slashes into the code with a replace call, but I was wondering if there is a better way to handle this? I have put together a couple of jsfiddles to illustrate what I am trying to describe: http://jsfiddle.net/qwUAJ/ (Stringify then parse back) var ob = {}; ob["number1"] = 'Number "1"'; ob["number2"] = 'Number 2'; ob["number3"] = 'Number 3'; var string = JSON.stringify(ob); var reOb = JSON.parse('{"number1":"Number \"1\"","number2":"Number 2","number3":"Number 3"}'); $('div').html(string); http://jsfiddle.net/a3gBf/4/ (Stringify, then print, then parse back) // Make an object var ob = {}; ob["number1"] = 'Number "1"'; ob["number2"] = 'Number 2'; ob["number3"] = 'Number 3'; // Turn the object into a JSON string var string = JSON.stringify(ob); // Printing the string outputs // {"number1":"Number \"1\"","number2":"Number 2","number3":"Number 3"} $('.stringified').html(string); // Attempt to turn the printed string back into an object var reOb = JSON.parse('{"number1":"Number \"1\"","number2":"Number 2","number3":"Number 3"}'); // This fails due to the single escaped quote marks. Thank you for any help in advance!
This is a problem which arises from re-evaluating a String without first converting it back into a string literal, so the meaning changes if it is even still valid. You need to consider what does '\"' as a literal actually mean? The answer is ", without the \. Why? \" resolves to " If you want to have \" as the result of the literal, you need to write '\\\"' \\ resolves to \ \" resolves to " So basically, the extra slashes are required to escape any characters with special meaning in string literals. If you did var reOb = JSON.parse($('.stringified').html()); it would work fine as is. Consider further str = '\\\"\\\''; // \"\' str = '\"\''; // "' str = '"''; // SyntaxError: Unexpected token ILLEGAL As far as I'm aware, JavaScript offers no native implementation to convert strings as desired, so the easiest method I know of is using a replace function toLiteral(str) { var dict = {'\b': 'b', '\t': 't', '\n': 'n', '\v': 'v', '\f': 'f', '\r': 'r'}; return str.replace(/([\\'"\b\t\n\v\f\r])/g, function ($0, $1) { return '\\' + (dict[$1] || $1); }); } toLiteral('foo\\bar'); // "foo\\bar"
If you generate JS with PHP code you should escape the quotes in your JSON string: //PHP code generating js code echo "var myJSONString = \"". str_replace("\"","\\\"",$mySqlJSON)."\";";