8

What I am trying to do is simple. Parse this array holding json objects into a Javascript array.

var merchantsJson = JSON.parse('[{"id":61693,"name":"Más"},{"id":61690,"name":"\u0027\u0022\u003C/div\u003E"}]');

But the unicode character \u003C seems to be breaking the parser. In the chrome console I see "Uncaught SyntaxError: Unexpected token <"

A little more info. The above is what the code is evaluated to. In reality the code contains a jsp expression.

var merchantsJson = JSON.parse('${jsonArr}');

If I remove the single quotes, there is no issue, but eclipse give me an "missing semicolon" error message. Is it possible to parse the array with the quotes as I am trying to do?

ikegami
  • 367,544
  • 15
  • 269
  • 518
mad_fox
  • 3,030
  • 5
  • 31
  • 43
  • You're getting a lot of responses similar to Juhana's comment, but note that JSON is not actually a subset of JavaScript. There are edge-cases where valid JSON will not be parsed correctly by a javascript interpreter that come about when you're working with Unicode: http://stackoverflow.com/questions/23752156/are-all-json-objects-also-valid-javascript-objects - be careful with this advice – Aaron Dufour Jun 30 '15 at 14:40
  • @AaronDufour I'm pretty sure JSP's JSON stringifier can handle those cases, considering it's designed to have its output inserted "as is" to the JS code. – JJJ Jun 30 '15 at 14:41
  • @Juhana I'm not familiar with JSP's JSON stringifier, so I figured a general warning was justified. If it can be trusted to `\u`-encode troublesome characters, then there won't be a problem. – Aaron Dufour Jun 30 '15 at 14:44
  • @AaronDufour Seeing from the question that it encodes characters like `<` and `>`, it's a rather safe bet that it also encodes characters that are known to break compatibility. – JJJ Jun 30 '15 at 14:47
  • @Juhana The variable name `jsonArr` indicates that OP has already done the stringifying, and I was not willing to assume that said stringification was aware of the intricacies of JSON vs JavaScript regarding Unicode. I see now that that is merely a misleading name. – Aaron Dufour Jun 30 '15 at 15:37

5 Answers5

12

The interpolation of ${jsonArr} is already a JavaScript object. When you wrap it in '${jsonArr}' this turns it into a string and you have to use JSON.parse.

There's no need to make it a string. You can just do var merchantsArray = ${jsonArr}. JSON constructs are already interoperable with JavaScript code.

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • 3
    Eclipse will complain that it's not legal JavaScript, but that's to be expected because it isn't JavaScript. It's a template that will produce JavaScript. – ikegami Jun 30 '15 at 14:37
  • 2
    This is the correct answer. Everyone else is treating the symptoms, not the cause. – JJJ Jun 30 '15 at 14:37
  • 5
    @Juhana, This is a correct answer if the JSON is trusted and if it's actually legal JS ([which not all JSON is](http://stackoverflow.com/questions/23752156/are-all-json-objects-also-valid-javascript-objects)). If it's not trusted, the correct answer is to properly convert the JSON into a JS string literal, which is what the other answers are suggesting (or trying to). They are not, as you say, treating the symptoms. – ikegami Jun 30 '15 at 14:38
  • 1
    @ikegami I'm under the assumption that `jsonArr` is being generated by his own code, but I agree that if it's coming from another source it could potentially be malicious. – Explosion Pills Jun 30 '15 at 14:43
  • 1
    The JSON is stringified by JSP. It's guaranteed to be safe. – JJJ Jun 30 '15 at 14:48
  • @Juhana: You're right about treating the actual cause being the proper approach, but I also think that on some level the OP is wondering why a string that looks valid at first glance doesn't parse. This answer will be the actual solution implemented but I think the other stuff is good for understanding it purely from the perspective of the parser. –  Jun 30 '15 at 14:57
  • @squint chose to omit this from my answer because it's covered so thoroughly in all the other answers. – Explosion Pills Jun 30 '15 at 14:58
  • @ExplosionPills: Yep, I have no problem with your answer. Just saying that both types of answers have merit. The *"corrrect"* answer in this case is a matter of perspective, though again your answer is definitely what should be implemented. –  Jun 30 '15 at 15:02
  • @Juhana, It's guaranteed not to contain U+2028 or U+2029? I doubt it! [JSON is not a subset of JS](http://stackoverflow.com/questions/23752156/are-all-json-objects-also-valid-javascript-objects). – ikegami Jun 30 '15 at 15:48
  • 1
    @ikegami It's guaranteed to utf-encode those characters, at which point they're not a problem. – JJJ Jun 30 '15 at 16:08
  • @Junhana, Of course they'll be encoded, and again, no, they're not allowed. Did you even followed the link I posted (twice)? – ikegami Jun 30 '15 at 16:33
  • 2
    @ikegami Yes, and you're misinterpreting it. It says that while those characters are illegal *as symbols*, they're legal when encoded (i.e. `"foo\u2028bar"` is legal both as JSON and as JS string.) – JJJ Jun 30 '15 at 16:56
  • 3
    The JSON is not trusted, that is why it is quoted. – mad_fox Jun 30 '15 at 17:12
  • @Juhana, I didn't misinterpret; you mispoke ("utf-encode"). Anyway, you were claiming that JSP is guarateed to convert U+2028 to `\u2028`? Then yeah, that would be fine. That's not required or common behaviour, though. – ikegami Jun 30 '15 at 17:44
8

Because there's an extra " in your string literal that is encoded by \u0022:

> '[{"id":61693,"name":"Más"},{"id":61690,"name":"\u0027\u0022\u003C/div\u003E"}]'
[{"id":61693,"name":"Más"},{"id":61690,"name":"'"</div>"}]

In short, your JSON in the string is invalid. You would need to escape the unicode escape sequences for the quotes in the string literal ("'\u0022</div>"), by using

JSON.parse('[{"id":61693,"name":"Más"},{"id":61690,"name":"\u0027\\u0022\u003C/div\u003E"}]'
//                                                               ^

or escape the quote character ("'\"</div>"):

JSON.parse('[{"id":61693,"name":"Más"},{"id":61690,"name":"\u0027\\\u0022\u003C/div\u003E"}]');
//                                                               ^^

However, there actually is no need to use JSON at all. Just output a JS array literal into your code:

var merchantsJson = ${jsonArr};
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Just wanted to note that the extra `\ ` in your last parsing example isn't really needed since JSON too will interpret the escape sequence. Works either way, just thought I'd mention it. –  Jun 30 '15 at 14:51
  • @squint: Yeah, that's like the first solution then :-) I maybe should've used `\\\"` for extra clarity. – Bergi Jun 30 '15 at 14:53
  • Yes, except that it unnecessarily escapes the single quotes, which have no special meaning to JSON, so those could just be received by the parser as actual quote characters instead of escape sequences. Again, just noting it for people because this escaping stuff can be confusing. It's all good and it all works. :-) –  Jun 30 '15 at 15:00
6

Try to replace \u with \\u. If you don't, JSON parser receives already decoded Unicode, which created polluted JSON.

Robo Robok
  • 21,132
  • 17
  • 68
  • 126
  • 4
    There's noting wrong with *decoded Unicode* in JSON... in fact it requires Unicode. The only real problem is that one character represents a double quote, which closes the *"sub-string"* that the parser is interpreting. That's the only one that needs escaping. –  Jun 30 '15 at 14:38
3

It's not because of \u003C, rather the \u0022 character is causing the issue, since it's a quotation mark and JavaScript treats it literally ending the string.

You need to escape that character: \\u0022 .

carraua
  • 1,398
  • 17
  • 36
  • `\u0027` isn't the problem; `\u0022` is. – Aaron Dufour Jun 30 '15 at 14:35
  • 1
    Yes, both can be the problem depending on how you start your string. – carraua Jun 30 '15 at 14:37
  • 3
    @AlejandroC: No, only the double quote is the problem. Doesn't matter what quotes you're using in the string literal because it's already an escape sequence, so it won't break the main string. –  Jun 30 '15 at 14:40
  • 1
    Thanks @squint http://stackoverflow.com/questions/19176024/how-to-escape-special-characters-in-building-a-json-string – carraua Jun 30 '15 at 14:50
0

you have to use special character in your JSON string, you can escape it using \ character.

you need to replace \ with \\.

[{\"id\":61693,\"name\":\"Más\"},{\"id\":61690,\"name\":\"\\u0027\\u0022\\u003C/div\\u003E\"}]
Reza Jenabi
  • 3,884
  • 1
  • 29
  • 34