Parsing JSON ( again ) in iOS - iphone

I'm just playing with the JSON parser in iOS it's working fine as a ( simple ) example . But I was wonder how one would actually parse something (a bit) more complicated, the a Twitter trends JSON, like this :
{
"trends": {
"2011-03-13 11:42:17": [
{
"events": null,
"query": "Fukushima",
"promoted_content": null,
"name": "Fukushima"
},
{
"events": null,
"query": "Rebecca Black",
"promoted_content": null,
"name": "Rebecca Black"
},
{
"events": null,
"query": "Pearl Harbour",
"promoted_content": null,
"name": "Pearl Harbour"
},
...
{
"events": null,
"query": "Magdalena Neuner",
"promoted_content": null,
"name": "Magdalena Neuner"
}
]
},
"as_of": 1300016537
}
How would one just return the first 3 queries ? in this instance : Fukushima, Rebecca Black and Pearl Harbour .
Using the example code, it goes something like this :
for (int i = 0; i < [luckyNumbers count]; i++)
[text appendFormat:#"%#\n", [luckyNumbers objectAtIndex:i]];
This is for a much simpler feed though, can it be approached the same way for what I'm looking for ?
I'm trying to return the value of "query":
So I`m doing this :
NSLog(#"%#", [[luckyNumbers objectForKey:#"trends"]);
This of course logs the content of the key "trend", how do I go about returning not only the first ( and only ) key of trends but also dig one more level down to return the content of "query" ??
I've also tried something like this :
NSString *date = [[[luckyNumbers valueForKeyPath:#"trends"] allKeys] description];
NSArray *trends = [luckyNumbers objectForKey:#"trends"];
NSLog(#"%#", [trends valueForKeyPath:date]);
but no go ...
EDIT (aftet honcheng's answer):
Because I want to iterate through the results of "trends", I'm doing :
NSDictionary *luckyNumbers = [responseString JSONValue];
NSArray *keys = [[luckyNumbers objectForKey:#"trends"] allKeys];
for (int i =0; i < [keys count]; i++) {
NSLog(#"%#", [keys objectAtIndex:i]);
}
Obviously something is wrong because I'm not getting any result ..

JSON parser usually returns native NSObjects such as NSDictionary and NSArray. After parsing, you just have to treat it like a new object.
[luckyNumbers allKeys] returns an NSArray ["trends", "as_of"]
[[luckyNumbers objectForKey:#"trends"] allKeys"] returns an NSArray ["2011-03-13 11:42:17"]
Since allKeys returns an NSArray, you can just use a for loop to get all your keys.

Related

AFNetworking valueForKeyPath Wildcard

Im trying to get the tvrage_name from the following JSON file.
{
data: {
Band of Brothers: {
air_by_date: 0,
cache: {
banner: 1,
poster: 1
},
language: "en",
network: "HBO",
next_ep_airdate: "",
paused: 0,
quality: "Any",
status: "Ended",
tvdbid: 74205,
tvrage_id: 2708,
tvrage_name: "Band of Brothers"
},
Breaking Bad: {
air_by_date: 0,
cache: {
banner: 1,
poster: 1
},
language: "en",
network: "AMC",
next_ep_airdate: "2013-07-14",
paused: 0,
quality: "HD",
status: "Continuing",
tvdbid: 81189,
tvrage_id: 18164,
tvrage_name: "Breaking Bad"
},
},
message: "",
result: "success"
}
Is there any way to have a wildcard in the valueForKeyPath?
So the valueForKeyPath would be: data.*.tvrage_name (the * would be the wildcard)
No. You will have to loop over the key/values like this*:
...
NSDictionary *data = [JSON valueForKey:#"data"];
for (NSString *movie in data) {
NSLog(#"tvrage_name: %#", [[data valueForKey:movie] valueForKey:#"tvrage_name"]);
}
...
*I like to be on the safe side so I always have extra checks. e.g. [JSON isKindOfClass:[NSDictionary class]], etc.
Hope it helps.
If you get a copy of the dictionary with just the tv show entries (not 'message' and 'result'), then you can do [[shows allValues] valueForKeyPath:#"tvrage_name"]
This should work since allValues gives you an array of dictionaries and so valueForKeyPath will in turn give you an array of values under the given key.
(However it's probably a bad idea to do this without additional checks or hardening when getting JSON over a network, in case the JSON is not structured as you expected)

Parsing JSON: brackets in response

I want to parse this JSON YouTube recently featured.
This is how I get the title of the videos:
NSString *response = [request responseString];
responseDict = [response JSONValue];
videoTitleArray = [responseDict valueForKeyPath:#"feed.entry.title.$t"];
And it works like I want it.
But I also want to display the author of the video.
But the following code for this does not work properly:
videoAuthorArray = [responseDict valueForKeyPath:#"feed.entry.author.name.$t"];
NSLog(#"%#", videoAuthorArray);
The list of the authors I get looks like this:
(
author 1
),
(
author 2
),
(
author 3
),
(
author 4
),
I can't display the names in for example a table view because of the brackets.
How can I display the author names like the video titles?
When you see an Author you see this:
"author":[{"name":{"$t":"mls"},"uri":{"$t":"http://gdata.youtube.com/feeds/api/users/mls"},"yt$userId":{"$t":"SZbXT5TLLW_i-5W8FZpFsg"}}]
this means: author is an array of author objects
each author object has: name object, a uri object and a yt$userId object
each of this objects described above is a NSDictionary
formated we have:
"author":[
{
"name": {
"$t":"mls"
},
"uri": {
"$t":"http://gdata.youtube.com/feeds/api/users/mls"
},
"yt$userId":{
"$t":"SZbXT5TLLW_i-5W8FZpFsg"
}
}
],
so if you have your videoAuthorArray each element is an NSDictionary and has this keys: name, uri and yt$userId
each of this objects has an NSDictionary with a single key: $t witch has the value

RestKit Object Mapping - One Entity, two mappings

After my last question was solved the JSON I'm receiving from the server changed to the following and I'm stuck handling the mapping to save the data with Core Data.
Entity
Key
- alias
- key
- keyType
- keyword
- unid
- until
JSON (from Server)
{
"documents": 1026,
"configuration":
{
...
},
"data":
[
{
"alias": "",
"key": "SALUTATION",
"keyType": "S",
"keyword": "Mr",
"unid": ""
},
...
{
"alias": "Automobile",
"key": "ACCOUNT_MARKET_SEGMENT",
"keyType": "A",
"keyword": "Automobile",
"unid": ""
}
],
"documentsFound": 770,
"maxCount": -1,
"since": "20120326200001",
"until": "20120326211309"
}
Now I want to map all the data from "data" plus the key "until" for the entity "Key" but can't find the right solution. My mapping so far to get the data looks like this and works well but misses the "until"-key, of course.
RKManagedObjectMapping* keyMapping = [RKManagedObjectMapping mappingForClass:[Key class]];
keyMapping.rootKeyPath = #"data";
[keyMapping mapKeyPath:#"key" toAttribute:#"key"];
[keyMapping mapKeyPath:#"keyword" toAttribute:#"keywordEN"];
[keyMapping mapKeyPath:#"alias" toAttribute:#"alias"];
keyMapping.setDefaultValueForMissingAttributes = YES;
Thanks for your ideas!
You are probably going to want to do two mappings. The first mapping will enclose the entire object and will have a relationship to the nested 'data' path.
RKObjectMapping *keyMapping = [RKObjectMapping mappingForClass:[Key class]];
[keyMapping mapAttributes:#"alias", #"key", nil];
[keyMapping mapKeyPath:#"keyword" toAttribute:#"keywordEN"];
RKObjectMapping *outerMapping = [RKObjectMapping mappingForClass:[Container class]];
[outerMapping mapKeyPath:#"data" toRelationship:#"keys" withMapping:keyMapping];
[outerMapping mapAttributes:#"since", #"until", "maxCount", "documentsFound", nil];
That will give you a new object with your metadata and then an array of the key objects on the keys attribute of your container. Rather than using the rootKeyPath, you can use the resourcePath based mapping registration on the 0.9.4 development branch (about to be released).

Reading a JSON string

I have a JSON String, in the format;
{
"name": "Alex",
"age": "12"
}
I know how to extract values from the above JSON. but at times, when there are no records in the database. i get a null value printed. (i undestand that this is not a valid JSON)
This null gets caught in the following if-condition.
SBJsonParser *parser = [SBJsonParser new];
NSDictionary *content = [pobjectWithString:[request responseString]];
if(!content){
NSLog(#" when its null it comes to this block");
return;
}
I need to read this value null and save it in a NSString. How can i do this ?
note: i have made use of ASIHTTPRequest to write the above code.
It's not clear what you're asking for. I think you want to detect when a null occurs (which you already seem to do with if(!content) ), then you want to create a string that either is empty, or has the word "null" in it. Why not:
if(!content) {
return #"null";
}
Of course, you could return whatever you wanted in the string.

Facebook Graph API: result in array or in json object

I have little bit confuse between graph api result.Can any one explain which default object method is facebook using when we fetch data via graph api. Have any application account setting for access data in json object or in array object, because some time i found user data in encrypted and some time non encrypted.
I found user email id in two way from facebook graph api.
One is:
{
"id": "100001114785800",
"name": "Stella Jackson",
"first_name": "Stella",
"last_name": "Jackson",
"link": "http://www.facebook.com/profile.php?id=100001114785800",
"birthday": "04/16/1987",
"gender": "female",
"email": "stella_ja#live.com",
"timezone": 5.5,
"locale": "en_US",
"updated_time": "2010-10-08T13:26:10+0000"
}
And second one is:
{
"id": "100001114785800",
"name": "Stella Jackson",
"first_name": "Stella",
"last_name": "Jackson",
"link": "http://www.facebook.com/profile.php?id=100001114785800",
"birthday": "04/16/1987",
"gender": "female",
"email": "stella_ja\u0040live.com",
"timezone": 5.5,
"locale": "en_US",
"updated_time": "2010-10-08T13:26:10+0000"
}
Have any idea?
Thanks
The '\u0040' is same as obfuscated or Unicode form of '#' symbol. Most Parsers can convert that to the original symbol.
Check this for list of Unicode character set.
http://www.alanwood.net/demos/ansi.html
#Vik i want to do the same thing, collect post info in array, try this if it work than see..
if (response.authResponse) {
var accessToken = response.authResponse.accessToken;
//var UserInfo = document.getElementById('UserInfo');
FB.api('/' + info.id + '/feed?access_token=' + accessToken,
{ limit: 20 },function(result) {
UserInfo.innerHTML = "Welcome, " + result.id + "!";
alert('Message: ' + result.id);
});
}
Use this to get the dictionary n value of email for ios
FbGraphResponse *fb_graph_response = [fbGraph doGraphGet:#"me" withGetVars:nil];
NSLog(#"getMeButtonPressed: %#", fb_graph_response.htmlResponse);
NSDictionary *dictionary=[fb_graph_response.htmlResponse JSONValue];
NSLog(#"%#",[dictionary valueForKey:#"email"]);
Hope it helps you.
The easiest way would be to take the email string and do something like this (objective c):
NSString *email = #"stella_ja\u0040live.com"; // or whatever you use to get it
email = [NSString stringByReplacingOccurencesOfString:#"\u0040" withString:#"#"];
So in other words, use string methods to replace "\u0040" with "#".
you can simply replace \u0040 with # but during this replace compiler will consider "\" as escape sequence and will skip this without making changes.
What you do like this below:
NSString *strEmail = #"stella_ja\u0040live.com";
[strEmail stringByReplacingOccurrencesOfString:#"\\u0040" withString:#"#"];
NSLog(#"strEmail: %#", strEmail);