I have a c# method that calls another method which returns back a string that is supposed to represent JSON. However, the string has escape characters in it:
public string GetPerson()
{
string person = repo.GetPerson(); //person is "{\"name\":jack,\"age\":\"54\"...
return person;
}
If I try to do a replace, there is no change:
string person = repo.GetPerson().Replace(#"\""", ""); //person still has escape characters
When I try to view person in the text viewer when debugging, the escape characters are not there--Visual Studio rips them off. But my javascript that calls this method does see the escape characters in the ajax response.
If I try to deserialize the person string into my C# User object, it does not deserialize properly:
User user = JsonConvert.DeserializeObject<User>(person);
What are my options? How can I either strip off the escape characters from the person string, or deserialize it correctly to the User object?
If a Console.WriteLine(person) shows those backslashes and quotes around the string (not just the string and quotes inside), then there is a double serialization issue. You could try first to deserialize it to a string, then to a type, like this:
User user = JsonConvert.DeserializeObject<User>(JsonConvert.DeserializeObject<String>(person));
Also, you could try to do:
string person = repo.GetPerson().Replace(#"\""", #"""");
If you have control over the API, check for double serialization on return. ASP does a default serialization, so usually you don't have to return a string with the object pre-serialized.
For webapi, use Ok(object), for ASP MVC, use Json(object, requestBehaviour) methods.
Related
I've escaped control characters and am feeding my validated JSON into JSON.parse and jQuery.parseJSON. Both are giving the same result.
Getting error message "Unexpected token $":
$(function(){
try{
$.parseJSON('"\\\\\"$\\\\\"#,##0"');
} catch (exception) {
alert(exception.message);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
Thanks for checking out this issue.
What's happening here is that there are two levels of backslash removal being applied to the string. The first is done by the browser's JavaScript engine when it parses the single-quoted string. In JavaScript, single-quoted strings and double-quoted strings are exactly equivalent (other than the fact that single-quotes must be backslash-escaped in single-quoted strings and double-quotes must be backslash-escaped in double-quoted strings); both types of strings take backslash escape codes such as \\ for backslash, \' for single-quote (redundant but accepted in double-quoted strings), and \" for double-quote (redundant but accepted in single-quoted strings).
In your JavaScript single-quoted string literal you have several instances of this kind of thing, which are meant to be valid JSON double-quoted strings:
"\\\\\"$\\\\\"#,##0"
After the browser has parsed it, the string contains exactly the following characters (including the outer double-quotes, which are unremoved because they are contained in a single-quoted string):
"\\"$\\"#,##0"
You can see that each consecutive pair of backslashes became a single literal backslash, and the two cases of an odd backslash followed by a double-quote each became a literal double-quote.
That is the text that is being passed as an argument to $.parseJSON, which is when the second level of backslash removal occurs. During JSON parsing of the above text, the leading double-quote signifies the start of a JSON string literal, then the pair of backslashes is interpreted as a single literal backslash, and then the immediately following double-quote terminates the JSON string literal. The stuff that follows (dollar, backslash, backslash, etc.) is invalid JSON syntax.
The problem is that you've embedded valid JSON in a JavaScript single-quoted string literal, which, although it happens to be valid JavaScript syntax by fluke (it wouldn't have been if the JSON contained single-quotes, or if you'd tried using double-quotes to delimit the JavaScript string literal), no longer contains valid JSON after being parsed by the browser's JavaScript engine.
To solve the problem, you have to either manually escape the JSON content to be properly embedded in a JavaScript string literal, or load it independently of the JavaScript source, e.g. from a flat file.
Here's a demonstration of how to solve the problem using your latest example code:
$(function() {
try {
alert($.parseJSON('{"key":"\\\\\\\\\\"$\\\\\\\\\\"#,##0"}').key); // works
alert($.parseJSON('{"key":"\\\\\"$\\\\\"#,##0"}').key); // doesn't work
} catch (exception) {
alert(exception.message);
}
});
http://jsfiddle.net/814uw638/2/
Since JavaScript has a simple escaping scheme (e.g. see http://blogs.learnnowonline.com/2012/07/19/escape-sequences-in-string-literals-using-javascript/), it's actually pretty easy to solve this problem in the general case. You just have to decide in advance how you're going to quote the string in JavaScript (single-quotes are a good idea, because strings in JSON are always double-quoted), and then when you prepare the JavaScript source, just add a backslash before every single-quote and every backslash in the embedded JSON. That should guarantee it will be perfectly valid, regardless of the exact JSON content (provided, of course, that it is valid JSON to begin with).
In your original problem, why do you need to do JSONparse in the first place? You could have easily gotten the object you wanted by just doing
var o = { blah }
by manually removing the single quotes you have around the curly braces rather than doing
$.JSONparse('{blah}')
Is there any reason for evaluating the string first (ie var s = '{blah}' and then doing $.JSONparse(s)) which is what your original code was doing? There shouldn't be a case where this is necessary. Since you mentioned somewhere that the string was produced by JSON.stringify, there shouldn't be a scenario where you need to explicitly store it into a variable (ie copy and paste it and put quotes around it).
The main problem here is the string produced by JSON.stringify, which is properly escaped, has been 'evaluated' once when you manually put braces around it. So the key is to make sure the string doesn't get 'evaluated'
Even if you wanted to pass the stringified variable to database or anything, there is no need to explicitly use quotes. One could do
var s = JSON.stringify(obj);
db.save("myobj",s)
var newObj = JSON.parse(db.load("myobj"))
The string is stored verbatim without getting evaluated, so that when you retrieve it, you would have the exact same string.
I have java object which is converted as JSON string using
String paramMap = new ObjectMapper().writeValueAsString(custPolicy.getParamMap());
model.addAttribute("testTypeMap", paramMap );
In the .jsp page, on load I'm trying to parse the testTypeMap and get object back;
var paramMap = JSON.parse('${testTypeMap}');
showTestType('File content', 'LINUX', paramMap);
The object has double quotes (") in one of the fields, and it is escaped with backslash () when it is converted as JSON sting in java, that is why we see "\"" (from view source)
var paramMap = JSON.parse('{"Filepath":"/home/status.txt","Search expression":"\""}');
But the above line says, "Uncaught SyntaxError: Unexpected string".
I have seen few posts and they say it need two parses, one for javascript and one for JSON. I tried to replace \" with \\" ; but in javascript \" is always ", so I could not replace it;
Any pointer for what I miss here?
The problem is that you're not encoding the string in ${testTypeMap} as a JavaScript literal. I'm unsure how to do it specifically in your framework, but it's akin to HTML encoding a string, but for JavaScript instead.
However!
In your specific example you can avoid using JSON.parse because JSON is already in a format consumable by JavaScript.
var paramMap = ${testTypeMap};
showTestType('File content', 'LINUX', paramMap);
With the resulting source sent to browser looking like:
var paramMap = {"Filepath":"/home/status.txt","Search expression":"\""};
Actually I was not knowing how to replace \" with \\" in javascript, as \" is always represented as " (just one quote without backslash).
So I did this replace in server side after converting to a JSON string using Jackson's ObjectMapper as below:
String paramMap = new ObjectMapper().writeValueAsString(custPolicy.getParamMap());
// need to replace any \" with \\" in javascript side
paramMap = paramMap.replace("\\\"", "\\\\\"");
model.addAttribute("testTypeMap", paramMap );
Now in client-side it shows as below:
var paramMap = JSON.parse('{"Filepath":"/home/cavirin/status.txt","Search expression":"\\""}');
and this works fine as javascript parse is already taken care in server side.
I need to save a string value in a cookie, and that string (a person's last name) may contain an apostrophe, like O'Bama.
I tried lastName.replace(/'/, "\'").toString(); but I get undefined in a cookie.
What am I doing wrong, and how should this be done correctly?
Use the escape() function in javascript:
lastname = escape(lastname);
To undo this operation just call unescape()...
This will encode all special chars to store them in your cookie.
Some reference: http://www.w3schools.com/jsref/jsref_escape.asp
you only need to escape the string using javascript function:
escape()
and unescape to get the actual value
unescape()
Within HTML, it is okay to have endline characters. But when I try to send HTML strings that have endline characters over AJAX to have them operated with JavaScript/jQuery, it returns an error that says that endline characters are illegal. For example, if I have a Ruby string:
"<div>Hello</div>"
and jsonify it with Ruby by to_json, and send it over ajax, parse it within JavaScript by JSON.parse, and insert that in jQuery like:
$('body').append('<div>Hello</div>');
then it does not return an error, but if I do a similar thing with a string like
"<div>Hello\n</div>"
it returns an error. Why are they legal in HTML and illegal in AJAX? Are there any other differences between a legal HTML string loaded as a page and legal HTML string sent over ajax?
string literals can contain line breaks, they just need to be escaped with a backslash like so:
var string = "hello\
world!";
However, this does not create a line break in the string, as it must be an explicit \n escape sequence. This would technically become helloworld. Doing
var string = "hello"
+ "world"
would be much cleaner
Specify the type of the ajax call as 'html'. Jquery will try to infer the type when parsing the response.
If the response is json, newlines should be escaped.
I'd recommend using a library to serialize json. You're unlikely to handle all the edge cases if you roll your own.
Strings in JavaScript MUST appear on a single line, with the exception of escaping that line:
var str = "abc \
def";
However note that the newline is escaped and will not appear in the string itself.
The best option is \n, but note that if it is already going through something that parses \n then you will need to double-escape it as \\n.
Seeing how you're already escaping the JSON properly by using to_json in Ruby, I do believe the bug is in jQuery; when there are newlines in the string it has trouble determining whether you meant to create a single element or a document fragment. This would work just fine:
var str = "<div>Hello\n</div>";
var wrapper = document.createElement('div');
wrapper.innerHTML = str;
$('body').append(wrapper);
Demo
My MVC Controller contains a collection that I want to pass to the view, so I do:
// myCollection is a list of objects
var j = new JavaScriptSerializer();
ViewBag.Data = j.Serialize(myCollection);
And on the view inside JS
var data = $.parseJSON('#Html.Raw(ViewBag.Data)');
.. which expands to look something like:
var data = $.parseJSON('[{"Value":2,"Fullname":"Value"}]');
This works fine, but if my Json string contains a double quote it get's escaped with a backslash, and the parseJson fails, like this:
$.parseJSON('[{"Value":2,"Fullname":"Value \" with double quote"}]');
How do I fix that?
Whilst the following is valid JSON, it doesn't stay like that when the string is in JavaScript as it will unescape first:
'[{"Value":2,"Fullname":"Value \" with double quote"}]'
JavaScript will first unescape this to become:
'[{"Value":2,"Fullname":"Value " with double quote"}]'
When JSON comes along, it obviously sees an unexpected character since the quote is now looking to end the string. What you need to do is double-quote (\\" works) these somehow, whether you want to do it at the JS end or .NET end is probably entirely up to you.
However, there's really no need to parse this using JSON at all and you can just use it as an object literal like so:
var data = #Html.Raw(ViewBag.Data);
which will convert to:
var data = [{"Value":2,"Fullname":"Value \" with double quote"}];
.. which is perfectly valid.
why not just create custom function, and call parseJSON inside of it. but replace \" before that?
function parseJson(str){
var temp = str.replace('\"', '"');
return $.parseJSON(temp);
}