SBJSON parsing issue with Twitter's GET trends/:woeid - objective-c

I am trying to understand an issue I am having when using sbjson to parse the following json returned by a call to Twitter's GET trends/:woeid
I am using the following URL: #"http://api.twitter.com/1/trends/1.json" and I get the following response: (truncated to save space)
[
{
"trends": [
{
"name": "Premios Juventud",
"url": "http://search.twitter.com/search?q=Premios+Juventud",
"query": "Premios+Juventud"
},
{
"name": "#agoodrelationship",
"url": "http://search.twitter.com/search?q=%23agoodrelationship",
"query": "%23agoodrelationship"
}
],
"as_of": "2010-07-15T22:40:45Z",
"locations": [
{
"name": "Worldwide",
"woeid": 1
}
]
}
]
Here is the code I'm using to parse and display the name and url:
NSMutableString *content = [[NSMutableString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding:NSUTF8StringEncoding];
[content replaceCharactersInRange:NSMakeRange(0, 1) withString:#""];
[content replaceCharactersInRange:NSMakeRange([content length]-1, 1) withString:#""];
NSLog(#"Content is: %#", content);
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *json = [parser objectWithString:content];
//NSArray *trends = [json objectForKey:#"trends"];
NSArray *trends = [json objectForKey:#"trends"];
for (NSDictionary *trend in trends)
{
[viewController.names addObject:[trend objectForKey:#"name"]];
[viewController.urls addObject:[trend objectForKey:#"url"]];
}
[parser release];
This is sample code that is broken because it was targeted to Twitter's GET trends call which is now deprecated. The code will only work if I manually remove the first '[' and last ']'. However if I don't remove those characters from the response, the parser returns a NSArray of one NSString element: the json response.
How should I correctly parse this response. Thanks in advance.

I worked the issue out myself, I was confused by the NSArray coming back with only one element that appeared to be a string.
The one element in the array was not an NSString but a NSDictionary, once I understood this I could approach the data correctly by assigning the element to a NSDictionary, then accessing the "trends' data with the appropriate key:
NSMutableString *content = [[NSMutableString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding:NSUTF8StringEncoding];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSArray *json = [parser objectWithString:content];
NSDictionary *trends = [json objectAtIndex:0];
for (NSDictionary *trend in [trends objectForKey:#"trends"])
{
[viewController.names addObject:[trend objectForKey:#"name"]];
[viewController.urls addObject:[trend objectForKey:#"url"]];
}
[parser release];
It's a bit cleaner using the newly released NSJSONSerialization provided by Apple:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSArray *json = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
NSDictionary *trends = [json objectAtIndex:0];
for (NSDictionary *trend in [trends objectForKey:#"trends"])
{
[viewController.names addObject:[trend objectForKey:#"name"]];
[viewController.urls addObject:[trend objectForKey:#"url"]];
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[viewController.serviceView reloadData];
}

Related

How do I retrieve JSON data not on it's top level in Objective-C?

I have JSON data that looks as such:
{
"dataset": {
"id": ,
"dataset_code": "",
"database_code": "",
"name": "",
"description": "",
"refreshed_at": "",
}
}
When I go to NSLog the JSON data using the "dataset" identifier it prints fine. However I want to access the next level of JSON data which is what I'm looking to use. However, when I try to NSLog the next level I get an error in xcode. My code looks as such:
NSString *query = #"jsonwebsite.com";
NSData *jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:query]];
_Array = [[NSMutableArray alloc] init];
_Array = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
So if I use this it's logs fine.
NSString *testString = [_Array valueForKey:#"dataset"];
NSLog(#"%#",testString);
But as mentioned, I'm looking for the next set of data and when I try this, it gives an error.
NSString *testString = [_Array valueForKey:#"name"];
NSLog(#"%#",testString);
It returns (null). How would I be able to access the name field in this JSON data?
There is a lot wrong with your code.
_Array = [[NSMutableArray alloc] init];
_Array = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
There is no point to creating an empty array in the first line, only to replace it with a different object in the second line.
Your data contains a dictionary of dictionaries, not an array. You should create a variable dictionary:
NSMutableDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
You should not use valueForKey to fetch values from your dictionary. That is a KVO method. Use objectForKey instead, or better yet, use modern dictionary syntax:
NSMutableDictionary *dataSet = dictionary[#"dataset"];
NSString *name = dataSet[#"name"];
if (name == nil) {
NSLog(#"name is nil");
}
else if (name.length == 0) {
NSLog(#"name is empty");
}
else {
NSLog(#"Name is %#", name);
}
your json is a NSDictionary not a NSMutableArray,you used a NSMutableArray to recieve a NSDictionary was wrong.
test this:
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
NSDictionary *subDict = dict[#"dataset"];
NSLog(#"%#", subDict);
NSLog(#"%#", subDict[#"name"]);
Change this code:
NSString *query = #"jsonwebsite.com";
NSData *jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:query]];
_Array = [[NSMutableArray alloc] init];
_Array = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
NSString *testString = [_Array valueForKey:#"name"];
NSLog(#"%#",testString);
into this:
NSString *query = #"jsonwebsite.com";
NSData *jsonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:query]];
_Array = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
NSDictionary *dataSet = [_Array objectForKey:#"dataset"];
NSString *testString = [dataSet objectForKey:#"name"];
NSLog(#"%#",testString);

Decode JSON to NSArray or NSDictionary

I hope to decode the JSON data below:
{
"content":
[
{
"1":"a",
"2":"b",
"3":"c",
"4":"d",
"mark":"yes"
}
]
}
Not sure if put it in NSArray or NSDictionary
Welcome any comment
which iOS version are you using? in iOS 5 you have the NSJSONSerialization class to parse JSON data, if you need to target older iOSs or MAC OSX you should use third parties lib such as SBJSON. The string posted will be a NSDictionary with an array with one dictionary. The array will be accessible using the key #"content"
In code:
NSString * jsonString = #"blblblblblb";
NSStringEncoding encoding;
NSData * jsonData = [jsonString dataUsingEncoding:encoding];
NSError * error=nil;
NSDictionary * parsedData = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
In SWIFT 2.0:
let jsonString = "blblblblblb"
let encoding = NSUTF8StringEncoding
let jsonData = jsonString.dataUsingEncoding(encoding)
guard let jData = jsonData else {return}
do {
let parsedData = try NSJSONSerialization.JSONObjectWithData(jData, options: [])
} catch let error {
print("json error: \(error)")
}
[UPDATE]
The NSJSONSerialization class is also available for 10.7 my comment wasn't correct.
That particular string will decode into an NSDictionary because the outermost thing is a JSON object which maps onto a NSDictionary for every JSON implementation I have ever seen. If you want to process an arbitrary string, you'll need to test what you get back
NSError *jsonError;
id parsedThing = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (parsedThing == nil)
{
// error
}
else if ([parsedThing isKindOfClass: [NSArray class]])
{
// handle array, parsedThing can be cast as an NSArray safely
}
else
{
// handle dictionary, parsedThing can be cast as an NSDictionary
// NB only dictionaries and arrays allowed as long as NSJSONReadingAllowFragments
// not specified in the options
}
stringWithContentsOfFile:encoding: is deprecated in iOS<6
for iOS 6+
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"contents" ofType:#"json"];
NSError * error=nil;
NSString *jsonString = [NSString stringWithContentsOfFile:filePath encoding:nil error:&error];
NSData * jsonData = [jsonString dataUsingEncoding:nil];
NSArray * parsedData = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
contents.json file is in your bundle.
You can do the following:
NSData *data = ...; //JSON data
NSError *jsonError = nil;
[NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
You will get back an NSDictionary containing an NSArray containing a single NSDictionary containing five NSString objects.
I used google speech recognition API and I was getting a json response which was not directly parsable on iOS. Results samples were like :
First I tried saying Hello 1 2 3 which was recognised without issues. Json response was :
{"result":[]}
{"result":[{"alternative":[{"transcript":"hello 123","confidence":0.59780568},{"transcript":"hello 1 2 3"}],"final":true}],"result_index":0}
Or when talked for too long, I got a 404 HTML like below :
<html><title>Error 400 (Bad Request)!!1</title></html>
And when I spoke gibberish , I got :
{"result":[]}
So to parse all such response, I used the below code :
NSString *msg = #"Could not synthesize !";
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"responseString: %#",responseString);
if([responseString containsString:#"transcript"]&&responseString.length>25)
{
responseString = [responseString stringByReplacingOccurrencesOfString:#"{\"result\":[]}" withString:#""];
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
if(dictionary!=nil)
if(dictionary.allValues.count>0)
{
NSArray *array =[dictionary valueForKeyPath:#"result.alternative.transcript"];
if(array)
{
NSArray *array2 = [array objectAtIndex:0];
if(array2)
{
NSLog(#"%#",[array2 objectAtIndex:0] );
msg = [array2 objectAtIndex:0];
};
}
}
}
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Google Response" message:msg delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
Hope this helps someone.

parse JSON in objectiveC (SBJSON) objects and arrays

So far I've discovered in JSON that everything enclosed in { } are objects (objC : NSDictionary) and anything enclosed in [ ] is an array (objC : NSArray).
I've read and re-read this article about the subject>
How to parse JSON into Objective C - SBJSON
I have a .json file with the data modeled like this:
http://elbee101.com/dummySchedule.json
...and now for the code:
SBJSON *parser = [[SBJSON alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://elbee101.com/dummySchedule.json"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *schedule = [parser objectWithString:json_string error:nil];
NSDictionary *day = [schedule objectForKey:#"day"];
NSArray *myList = [day objectForKey:#"name"];
NSLog(#"myList %#", myList);
NSArray *numLaps = [myList objectAtIndex:0];
NSLog(#"numlaps%# ", numLaps);
I'm getting "myList (null)" and "numlaps (null)" from the above code?!#
The question: Can somebody please set me straight on the ordering of objects and arrays with respect to my json data? I want to drill down the tree so that I can access the 'day name', 'session starttime/endtime/sessionname', 'numlaps' & 'class' but I can't seem to get past the 'day' object/array(?)
What you're referring to as schedule is the object enclosed in the outermost {}. Try this:
NSDictionary *json = [parser objectWithString:json_string error:nil];
NSDictionary *schedule = [json objectForKey:#"schedule"];
Then continue as before.
Also, if you're on iOS 5 you can use the NSJSONSerialization class -- using it is pretty much the same, you might get better performance, and you don't have to worry about the hassles of using a third-party library.
call this where ever u need to parse
NSMutableArray *arr=[[NSMutableArray alloc] init];
arr=[[Headparse getArrayFromUrl:#"http://elbee101.com/dummySchedule.json"] retain];
NSLog(#"%#",[arr description]);
[arr release];
write this method as custom class use when ever you need
+(NSMutableArray *) getArrayFromUrl: (NSString *)actionType
{
NSMutableData *responseData1= [NSMutableData data] ;
responseData1 = [NSMutableData dataWithContentsOfURL:[NSURL URLWithString:actionType]];
// NSLog(#"%#",responseData1);
NSString *responseString1 = [[NSString alloc] initWithData:responseData1 encoding:NSUTF8StringEncoding];
//NSLog(#"REs:-->%#",responseString1);
//[responseData1 release];
responseData1 = nil;
NSMutableArray *responseArray = [[NSMutableArray alloc]init];
responseArray = (NSMutableArray *)[responseString1 JSONValue];
// NSLog(#"ghfchfvghv%#",responseArray);
[responseString1 release];
return responseArray;
}
This is how i use NSJsonSerialization for parsing the json object.
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://elbee101.com/dummySchedule.json"]];
NSError *err;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&err]; //
NSDictionary *schedule_dict = [json objectForKey:#"schedule"];
NSArray *days = [schedule_dict objectForKey:#"day"];//Days Array from day Object
NSDictionary *dayOne = [days objectAtIndex:0];
NSDictionary *dayTwo = [days objectAtIndex:1];
NSLog(#"THE DAY ONE : %#",dayOne);
NSLog(#"THE DAY TWO : %#",dayTwo);
Hope this may help you ....Note : If you don't want to go with NSJsonSerailization(consider reading of this) ,but still the parsing of json data like above will applicable in your case too.

Want to split the JSON from the URL not the response

I want to split the json part from this URL in my iPhone application.
http://vkontakte.ru/login_success.html#session={"expire":"1272008089","mid":"100172","secret":"9c8d8f0305","sid":"1131703552161ae352a1256402e3140d7cbde41b1602a93d15472c82"}
I tried and and saved the JSON into a NSString but what i am getting is
http://vkontakte.ru/api/login_success.html?session=%7B%22mid%22:113158415,%22secret%22:%227ce58bfcd3%22,%22sid%22:%2203831b43c1bb992f9477efbfe96e83f6ecff1c1b661315ac0a20719cf57a44%22,%22expire%22:0%7D
This is not coming in JSOn Format. Below is my code
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
NSError* error;
NSLog (#"json path %#",url);
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSURLRequest *request1 = [NSURLRequest requestWithURL:url];
NSString *json_string = [url absoluteString];
NSArray *arr = [json_string componentsSeparatedByString:#"="];
json_string = [arr objectAtIndex:1];
// parse the JSON response into an object
// Here we're using NSArray since we're parsing an array of JSON status objects
NSArray *statuses = [json_string JSONValue];
NSLog(#"%#",error);
// Each element in statuses is a single status
// represented as a NSDictionary
for (NSDictionary *status in statuses)
{
// You can retrieve individual values using objectForKey on the status NSDictionary
// This will print the tweet and username to the console
NSLog(#"%# - %#", [status objectForKey:#"secret "], [[status objectForKey:#"mid"] objectForKey:#"sid"]);
}
return YES;
}
How can move further?
Try replacing:
NSString *json_string = [url absoluteString];
with
NSString *json_string = [[url absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];.
That's a really strange thing you're doing, though. Why does the URL have JSON in it?

Parsing nested JSON objects with JSON Framework for Objective-C

I have the following JSON object:
{
"response": {
"status": 200
},
"messages": [
{
"message": {
"user": "value"
"pass": "value",
"url": "value"
}
]
}
}
I am using JSON-Framework (also tried JSON Touch) to parse through this and create a dictionary. I want to access the "message" block and pull out the "user", "pass" and "url" values.
In Obj-C I have the following code:
// Create new SBJSON parser object
SBJSON *parser = [[SBJSON alloc] init];
// Prepare URL request to download statuses from Twitter
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:myURL]];
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// Get JSON as a NSString from NSData response
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
//Print contents of json-string
NSArray *statuses = [parser objectWithString:json_string error:nil];
NSLog(#"Array Contents: %#", [statuses valueForKey:#"messages"]);
NSLog(#"Array Count: %d", [statuses count]);
NSDictionary *results = [json_string JSONValue];
NSArray *tweets = [[results objectForKey:#"messages"] objectForKey:#"message"];
for (NSDictionary *tweet in tweets)
{
NSString *url = [tweet objectForKey:#"url"];
NSLog(#"url is: %#",url);
}
I can pull out "messages" and see all of the "message" blocks, but I am unable to parse deeper and pull out the "user", "pass", and "url".
Solved:
NSArray *tweets = [[results objectForKey:#"messages"] valueForKey:#"message"];
Array({
0=>Dictionary({
response = Array({
0=>Dictionary(Status = 200)
})
}),
1=>Dictionary({
messages = Array({
0=> Dictionary({
message = Array({
0=>Dictionary({
user = value,
pass=value,
url=value
})
})
})
})
})
})
So, to access dictionary for user, pass, url,
nsarray *arr = jsonmainarray;
arr = [[[jsonmainarray objectAtIndex: 1] objectforkey:#"messages"] objectatindex: 0];
nsdictionary *dict = [arr objectatindex: 0];
arr = [dict objectforkey:#"message"];
dict = [arr objectatindex: 0]; // Dictionary with user, pass, url
there is an easier way (in my opinion) to do JSON parsing :)
- (void)loadJSONData:(NSString *)u{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://expandurl.appspot.com/expand?url=%#", u]];
NSData *rawJsonData = [NSData dataWithContentsOfURL:url];
CJSONDeserializer *parser = [CJSONDeserializer new];
NSError *error;
NSDictionary *jsonDictionary = [parser deserializeAsDictionary:rawJsonData error:&error];
[parser release];
NSArray *array = [jsonDictionary objectForKey:#"urls"];
}
All you have to do is to use JSON touch... like Sheehan Alam mention.
Say that you got this line of JSON data:
{
"end_url" = "http://www.youtube.com";
redirects = 0;
"start_url" = "http://www.youtube.com";
status = OK;
urls = (
"http://www.youtube.com"
);
}
then in your JSONDictonary the data can be accessed by doing:
[jsonDictionary objectForKey:#"urls"]; //This will return an Array since URLS is a array
[jsondictionary objectForKey:#"en_url"]; //this will return an NSString since end_url is a string
Hope this help people as much as it helped me =)
sincerely yours
Kristian