Best way to parse a JSONP response - objective-c

I am calling an API, which should return a JSON file. Here is the API link: http://sg.media-imdb.com/suggests/h/hello.json
The problem is: this JSON file has something wrapping the JSON response
imdb$hello(JSON)
So the best approch that I can see is to use a regex expression to extract only what I need. Something like: ~/\((.*)\)/.
However I would like to use the new JSON iOS5 API, which (as far as i know) only accepts NSData as input. So, I don't want to convert my response from NSData to NSString, parse that using regex, and put that in another NSData object.
Can anyone see a better/cleaner solution for that JSON parsing?

What you have isn't JSON, but JSONP. If you're not in JavaScript, I believe the correct way to handle is just as you say, preprocess and then parse.

NSError *jsonError = nil;
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSRange range = [jsonString rangeOfString:#"("];
range.location++;
range.length = [jsonString length] - range.location - 1;
jsonString = [jsonString substringWithRange:range ];
NSJSONSerialization *jsonResponse =
[NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:&jsonError];

Why don't you just do something like this before parsing the JSON?
response = [response stringByReplacingOccurrencesOfString:#"imdb$hello" withString:#""];

How regular is this string. It will always be there?
// Remove #"imdb$hello(" and #")" that wraps the response string.
NSRange JSONRange = NSMakeRange(11, [responseString length] - 12);
NSString *JSONString = [responseString substringWithRange:JSONRange];
// Now you can parse as normal…
You will need to craft the method of peeling away the wrapper with your own level of certainty.

Related

Unable to decode gzipped Base64 NSString

So I'm trying to decode a base64 encoded string but I'm not having any luck.. decodedString is always null! I've tried for hours and totally out of ideas. Even tried third party libraries.
Code:
NSString *input = #"H4sIAAAAAAAEALWSTW/TQBCG/0q15wTN7Je9voU2RFFUFCnuASGE9mMcTB0n9QcSQvx3xm6QWsSFAzev53l3Zp9dcb8+HFab9fZOFGJ/3Ny+bbvdrt+MX56ePp9OeDyKhSi3TJWr+z0zEtAtQS1RligLowowbxSAzqWdyA/7NUMP+7tVueb12FPXi5vi5uOP+XubuJoHkpjQOghBW5c5Dzpo0sZj8FYaztVtP6MSeHG+XIMKpJQEQQcgnSobrHVRxco6qY2WcgoOdHq4NkKzENV7fyKOrnx3brneXNeHoavjY+PbxD+jb6hNfg7BQlCqh7Kesb+eNkfjZM65R/o+zxUpwxAzTyoinyL5hLnPJBkbK6h8YPTSnb9SHGbcGcgQfJDBWY0qhop5ixoJdRYUMZ6oedf44zzO5G1ftxxEqbSx4uenufVvr/9vile3MJndPbeaxPaD715YskswS4WlxAKhgCnASv+wKPMSTYHuuf7NN3XyA92ex3bgTdU/mB8vU/Iw+GHsOfpa2MvrFEGBTSEjrPiRVImCT8T7qJSMs5VJbPMX5JgDcAQDAAA=";
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:input options:0];
NSString *decodedString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
NSLog(#"Decode String Value: %#", decodedString);
The Base64 decoded output is not a string, it is binary data.
You are getting nil returned because it is not a UTF-8 string and arbitrary data is generally not valid UTF-8.
Decode using NSDataBase64DecodingIgnoreUnknownCharacters to avoid the decoder discarding non-Base-64 bytes.
NSData *decodedData = [[NSData alloc]initWithBase64EncodedString:input
options:NSDataBase64DecodingIgnoreUnknownCharacters];
Once you have decodedData, you can decompress the buffer with whatever function or library you decide on, then you can read the string. You may want to look at the answer here for an idea of how to decompress your data.
decodedData is not nil.
It's value is: <1f8b0800 ...
1f8b let me think it's a GZip.
Any hex data is not convertible as such into a String using UTF8 Encoding. UTF8 doesn't have value for each possible hex. There are non-valid combination, and so your final string is nil.
For instance, transform an UIImage into PNG HexData (using UIImagePNGRepresentation()) and try it to convert it into a NSString using NSUTF8StringEncoding. You'll see.
Using the code of https://github.com/nicklockwood/GZIP/ (first one I found):
NSData *unzippedData = [decodedData gunzippedData];
NSString *decodedString = [[NSString alloc] initWithData:unzippedData encoding:NSUTF8StringEncoding];
Output:
"MESSAGEID":"PgGCBnrKKsGuhqq_mm1gg","TIMESTAMP":"2019-03-12T12:53:05.3004826","TYPE":"UPDATE","users" : [{"userId":"8be21d1690bb46979a04b4e45a1ba625","insId":"20","operId":"30222e0b4b0e4df6b669c3cf69245422","itemUserId":15,"fName":"Aaron","lName":"Strickland","calendarId":0,"editTime":"2019-03-12T12:53:05.3815928","keyId":"ce71bc7ae3c145adad18a72e56cf0fab","projectId":"950710ab2b96413cbfd186141e147b3e","delFlag":0,"userPin":"123456"}],"keys" : [{"keyId":"ce71bc7ae3c145adad18a72e56cf0fab","projectId":"950710ab2b96413cbfd186141e147b3e","insId":"20","itemKeyId":15,"startTime":"2016-05-31T21:10:00","endTime":"2019-03-28T15:19:00","validateCount":13,"editTime":"2019-03-12T12:53:05.3815928","updateStatus":1,"delFlag":0,"calendarId":"b306db7e1f924fdebade3813dd596f5d"}]
Seems almost like JSON. I would have add "{" and "}" around it.
With a little of workaround:
NSMutableData *finalData = [[NSMutableData alloc] initWithData:[#"{" dataUsingEncoding:NSUTF8StringEncoding]];
[finalData appendData:unzippedData];
[finalData appendData:[#"}" dataUsingEncoding:NSUTF8StringEncoding]];
NSData *dictionary = [NSJSONSerialization JSONObjectWithData:finalData options:0 error:nil];
NSLog(#"dictionary: %#", dictionary);
It's up to you to know why the syntax is strange, but with that you a "usable" NSDictionary.

How to parse HTML JSON String

I am troubling to parse JSON from Html String, Please suggest me better way to parse.
<html><head></head><body>{"data":{"type":"success","message":"Thanks for order with XYZ."}}</body></html>
This Html string response from stringByEvaluatingJavaScriptFromString API.
I want to parse "type" and "message" from above string. I am not getting expected result from rangeOfString API.
Thanks in advances.
Assuming you need this as a dictionary in Obj-C:
NSString * html = #"<html><head></head><body>{\"data\":{\"type\":\"success\",\"message\":\"Thanks for order with XYZ.\"}}</body></html>";
NSData * data = [html dataUsingEncoding:NSUTF8StringEncoding];
NSAttributedString * attributedString = [[NSAttributedString alloc] initWithHTML:data documentAttributes:nil];
NSData * jsonData = [attributedString.string dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary * result = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
NSLog(#"Output %#",result);

Incorrect result from NSJSON Serialization

I have got a very strange issue when I trying to deserialize my json string, the code is this:
NSString *testString = #"{\"cash\": 99946.222300000000}";
// NSString *testString = #"{\"cash\": \"99946.222300000000\"}"; //It's correct if I use this one
NSData *jsonData = [testString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];
NSLog(#"Convertion result is %#",error?#"false":#"true");
NSLog(#"Result data is\n %#",jsonObject);
And the result is :
2017-08-30 18:04:36.430 DAE[45557:2989692] Conversion result is true
2017-08-30 18:04:36.430 DAE[45557:2989692] Result data is
{
cash = "99946.22229999999";
}
So can anybody tell me if I did anything wrong? and how to solve it?
Really appreciate for any help.
First of all, it’s not wrong, it’s correct.
So, why you got the incorrect result?
First, The json value will be converted to a NSNumber object by NSJSONSerialization;
Then, the -description method of NSDictionary generate the result by stringValue method.
You should resolve the json value by this way to get the correct string:
[NSString stringWithFormat:%lf, [jValue doubleValue]]
But you should pay attention to the length of the value, the max length of double is 16, so if you get a number over than it, you will never get the correct result.
Tell your backend guy that they should convert all the numbers to string before they give them out, because it’s really hard to resolve them correctly if it’s big enough.
use it as Your commented string
NSString *testString = #"{\"cash\": \"99946.222300000000\"}";
NSData *jsonData = [testString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingAllowFragments error:nil];
NSLog(#"Convertion result is %#",error?#"false":#"true");
NSLog(#"Result data is\n %#",jsonObject);

JSON Parsing, Objective c

callback({"success":"TRUE","total_records":1,"data":[{"status_value":"1","status_text":"Login Successful","user_id":"5","u_name":"Tushar Verma"}]})
I have a service which gives the above result, so how can i get the data value using json parsing in objective c.
Thanks for the help in advance.
The NSJSONSerialization is available to iOS from 5.0 onwards.
It provides convenient methods to convert the data representation of JSON response from a server to the appropriate NSArray or NSDictionary methods.
It's harder to give a more detailed answer as you've asked such a general question.
use this simple code :-
NSString *str = #"{\"success\":\"TRUE\",\"total_records\":1,\"data\":[{\"status_value\":\"1\",\"status_text\":\"Login Successful\",\"user_id\":\"5\",\"u_name\":\"Tushar Verma\"}]}";
NSData *data = [str dataUsingEncoding:NSASCIIStringEncoding];
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSArray *arr =[dic objectForKey:#"data"];
NSLog(#"%#", arr);

prepend NSString?

I am getting a JSON response from a web service but it is not wrapped by the [] tags required by the JSON parser I am using so I need to Append and Prepend those characters to my NSString before I pass that to the JSON parser.
Here is what I haver so far:
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
responseString = [responseString stringByAppendingFormat:#"]"];
The appending works perfectly now I just need to prepend the [ to this, can't seem to find this method.
Try this:
responseString = [NSString stringWithFormat:#"[%#]", responseString]
There are other ways of acheiving the same thing, I'm sure others will be able to provide more efficient methods, but if responseString isn't very large then the above should suffice.
Using a NSMutableString you can do it like this:
NSMutableString *str = [[NSMutableString alloc] initWithString:#"Overflow"];
[str insertString:#"Stack" atIndex:0];
After that the NSMutableString str will hold:
"StackOverflow"
Just for completeness:
responseString = [#"[" stringByAppendingString:responseString];
It sometimes surprises folks that you can message a string literal, until they think about it. ;)