I'm parsing an XML and saving result to NSMutableArray. When I do NSLog,
NSLog(#"Data : %#",_data);
I'm getting
Data : (
{
SessionToken = 9e72dd029e0e8268380b919356881935;
}
)
I only want 9e72dd029e0e8268380b919356881935 from the array. What is the best solution to achieve this?
EDIT : There will be only one SessionToken at a time.
You can try this code :
for (NSDictionary *data1 in _data) {
NSlog("session token %#",[data1 objectForKey:#"SessionToken"]);//Other wise add into another array which contain session token.. only..
}
Since there will be only one session at a time.
NSDictionary *session = [_data lastObject];
NSString *sessionToken = session[#"SessionToken"];
OR with literals
NSString *sessionToken = _data[0][#"SessionToken"];
if ([_data count]) {
NSDictionary *dic = [_data objectAtIndex:0];
NSLog(#"Data : %#",[dic objectForKey:#"SessionToken"]);
}
for (NSDictionary *data1 in _data) {
NSlog("session token %#",[data1 valueForKey:#"SessionToken"]);
}
When I call the SBJsonParser the first time, it's working fine but on the second try, the result is always null. The data format is exactly the same as the first.
Here is the code:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
// the connection finished loading all data, process...
// Store incoming data into a string
NSString *jsonString = [[NSString alloc] initWithData:self.jsonData encoding:NSUTF8StringEncoding];
NSLog(#"%#",jsonString);
if ( jsonString != nil ) {
// Create SBJSON object to parse JSON
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *results =
[parser objectWithString:jsonString error:nil];
NSLog(#"results: %#", results);
if ( [[results objectForKey:#"postalCodes"] count] > 0 ) {
// Build an array from the dictionary for easy access to each entry
NSArray *postalCodes_array = [results objectForKey:#"postalCodes"];
int index = 0;
// Loop through each entry in the dictionary...
for (NSDictionary *dict_item in postalCodes_array)
{
if ( index == 0 ) {
appDelegate.curZip = [dict_item objectForKey:#"postalCode"];
NSLog(#"New Zip: %#", appDelegate.curZip);
break;
}
}
postalCodes_array = nil;
parser = nil;
}
results = nil;
}
jsonString = nil;
}
Here are the print out for NSLog lines above:
First try:
2012-05-27 12:19:13.322[16525:707] {"postalCodes": [{"adminName2":"Union","adminCode2":"039","distance":"0","adminCode1":"NJ","postalCode":"07201","countryCode":"US","lng":-74.2099,"placeName":"Elizabeth","lat":40.661369,"adminName1":"New Jersey"},{"distance":"0.28183","adminCode1":"NJ","postalCode":"07216","countryCode":"US","lng":-74.210939,"placeName":"Elizabeth","lat":40.663778,"adminName1":"New Jersey"},{"distance":"0.28183","adminCode1":"NJ","postalCode":"07215","countryCode":"US","lng":-74.210939,"placeName":"Elizabeth","lat":40.663778,"adminName1":"New Jersey"},{"adminName2":"Union","adminCode2":"039","distance":"1.12041","adminCode1":"NJ","postalCode":"07202","countryCode":"US","lng":-74.221544,"placeName":"Elizabeth","lat":40.65652,"adminName1":"New Jersey"},{"adminName2":"Union","adminCode2":"039","distance":"1.72655","adminCode1":"NJ","postalCode":"07206","countryCode":"US","lng":-74.192487,"placeName":"Elizabeth","lat":40.653207,"adminName1":"New Jersey"}]}
Second Try:
2012-05-28 20:16:16.727 [17151:707] {"postalCodes":[{"adminName2":"Kings","adminCode2":"047","distance":"0","adminCode1":"NY","postalCode":"11230","countryCode":"US","lng":-73.956528,"placeName":"Brooklyn","lat":40.618122,"adminName1":"New York"},{"adminName2":"Kings","adminCode2":"047","distance":"1.38292","adminCode1":"NY","postalCode":"11210","countryCode":"US","lng":-73.946682,"placeName":"Brooklyn","lat":40.628064,"adminName1":"New York"},{"adminName2":"Kings","adminCode2":"047","distance":"2.04126","adminCode1":"NY","postalCode":"11229","countryCode":"US","lng":-73.94749,"placeName":"Brooklyn","lat":40.601094,"adminName1":"New York"},{"adminName2":"Kings","adminCode2":"047","distance":"2.45579","adminCode1":"NY","postalCode":"11204","countryCode":"US","lng":-73.985623,"placeName":"Brooklyn","lat":40.617871,"adminName1":"New York"},{"adminName2":"Kings","adminCode2":"047","distance":"2.70498","adminCode1":"NY","postalCode":"11223","countryCode":"US","lng":-73.974291,"placeName":"Brooklyn","lat":40.597874,"adminName1":"New York"}]}{"postalCodes":[{"adminName2":"Richmond","adminCode2":"085","distance":"0","adminCode1":"NY","postalCode":"10306","countryCode":"US","lng":-74.141922,"placeName":"Staten Island","lat":40.564416,"adminName1":"New York"},{"adminName2":"Richmond","adminCode2":"085","distance":"0.41508","adminCode1":"NY","postalCode":"10313","countryCode":"US","lng":-74.146836,"placeName":"Staten Island","lat":40.564393,"adminName1":"New York"},{"adminName2":"Richmond","adminCode2":"085","distance":"1.66907","adminCode1":"NY","postalCode":"10308","countryCode":"US","lng":-74.152649,"placeName":"Staten Island","lat":40.55181,"adminName1":"New York"},{"adminName2":"Richmond","adminCode2":"085","distance":"3.76947","adminCode1":"NY","postalCode":"10312","countryCode":"US","lng":-74.179165,"placeName":"Staten Island","lat":40.545745,"adminName1":"New York"},{"adminName2":"Richmond","adminCode2":"085","distance":"4.41459","adminCode1":"NY","postalCode":"10314","countryCode":"US","lng":-74.147218,"placeName":"Staten Island","lat":40.603915,"adminName1":"New York"}]}
2012-05-28 20:16:16.760 [17151:707] error: Error Domain=org.brautaset.SBJsonParser.ErrorDomain Code=0 "Token 'start of object' not expected after outer-most array or object" UserInfo=0x176560 {NSLocalizedDescription=Token 'start of object' not expected after outer-most array or object}
2012-05-28 20:16:16.761 [17151:707] results: (null)
As you can see, I am doing the init every time. Not sure why it's not working. Any suggestion is appreciated.
Thank you
In your second try the JSON is not valid. That is why it is not being parsed. You can check it here: http://jsonlint.com/
At the end of the JSON string it seems like some junk has been inserted. If you format the string you will find the problem at lines 51-53. Replace the following with a comma:
]
}{
"postalCodes":
On closer inspection it looks like you are only interested in placeName == "Elizabeth". At the very end you have one entry where placeName == "Fanwood". So you probably just want to remove lines 51-62.
As an aside, you could use the error parameter to detect problems with your parser.
NSError *error = nil;
NSDictionary *results = [parser objectWithString:jsonString error:&error];
if (error) {
// we have a problem
}
Why an unexpected array braces closing here?in your second json sring?
"placeName":"Elizabeth","lat":40.653207,"adminName1":"New Jersey"}]}{"postalCodes":{"adminName2":"Union","adminCode2":"039","distance":"3.97758","adminCode1":"NJ","postalCode":"07023","countryCode":"US","lng":-74.386762,"placeName":"Fanwood","lat":40.641856,"adminName1":"New Jersey"}]} .
Its not an issue of init.its an error in the jsonstring that you are getting.
I need to make the json params like below.
Final output should be,
{"submissionTime":"\/Date(1331549630849)\/",
"statusId":"0",
"answers":[{"answer":"Yes","qid":167},{"answer":"Hello","qid":168}],
"participantId":"16369",
"token":"t_ikHOXVjlcsSb9Tfdn5RaO54JGQobHodUD5881SKevxy63jwLxe8ZPQvXYss4pR"}
I am trying to make this format. I got the time, statusid, participantid and token. Its fine. But, i am facing problem when making "answers" array.
I use the below code for making the answers json format like below.
NSArray *answerkeys = [NSArray arrayWithObjects:#"answer", #"qid",nil];
NSString *qID = [NSString stringWithFormat:#"%d", [questionidArray objectAtIndex:i] ]; // for loop
NSArray *objectkeys = [NSArray arrayWithObjects:value, qID,nil];
NSString *answerjsonRequest = [pSr makeJSONObject:objectkeys :answerkeys];
answerjsonRequest = [(NSString *)answerjsonRequest stringByReplacingOccurrencesOfString:#"\n" withString:#""];
[textvaluesArray addObject:[NSString stringWithFormat:#"%#", answerjsonRequest]];
and the output is like below.
(
"{ \"answer\" : \"Hello\", \"qid\" : \"220421824\"}",
"{ \"answer\" : \"How are you\", \"qid\" : \"115781136\"}"
)
But, when i am adding all in one in the final output like below,
NSString *jsonRequest = [pSr makeJSONObject:[NSArray arrayWithObjects: participantID, (NULL!=textvaluesArray)?textvaluesArray:#"0", [NSString stringWithFormat:#"%d", statusID], subTime, [appDelegate getSessionToken], nil] :[NSArray arrayWithObjects:#"participantId", #"answers", #"statusId", #"submissionTime", #"token", nil] ];
The final json result is this.
{
"submissionTime" : "\/Date(1331566698)\/",
"token" : "t_hvYoxifLQhxEKfyw1CAgVtgOfA3DjeB9jZ3Laitlyk9fFdLNjJ4Cmv6K8s58iN",
"participantId" : "16371",
"answers" : [
"{ \"answer\" : \"Hello\", \"qid\" : \"220421824\"}",
"{ \"answer\" : \"Hello\", \"qid\" : \"115781136\"}"
],
"statusId" : "0"
}
BUT, this is NOT the one what i want. My expected JSON output is top above mentioned. I tried many ways, but couldn't achieve this. Could someone helping me on this to resolve to get the exact JSON output?
Thank you!
I ran into this issue as well, and created a quick category to take care of the problem.
#interface NSString (ReplaceForJSON)
- (NSString*)replaceEscapedQuotes;
#end
#implementation NSString (ReplaceForJSON)
- (NSString*)replaceEscapedQuotes
{
NSString* returnVal = [self stringByReplacingOccurrencesOfString:#"\\\"" withString:#"\""];
returnVal = [returnVal stringByReplacingOccurrencesOfString:#"\"{" withString:#"{"];
returnVal = [returnVal stringByReplacingOccurrencesOfString:#"}\"" withString:#"}"];
return returnVal;
}
#end
This is what my JSON return;
{
"1": {
"name": "Sharon",
"telephone": "48-9929329483"
},
"2": {
"name": "Sage",
"telephone": "48-9560333267"
},
"3": {
"name": "Alex",
"telephone": "48-8467982378"
}
}
I need to save this in a NSDictionary. My workings are as follows;
NSDictionary *contentOfDictionary = [responseString JSONValue];
NSDictionary* studentDictionary = [contentDictionary objectForKey:#"1"];
NSString *nameOfStudent = [studentDictionary objectForKey:#"name"];
NSString *nameOfStudent = [studentDictionary objectForKey:#"telephone"];
NSDictionary* studentDictionary1 = [contentDictionary objectForKey:#"2"];
NSString *nameOfStudent1 = [studentDictionary objectForKey:#"name"];
NSString *nameOfStudent1 = [studentDictionary objectForKey:#"telephone"];
..... etc
So this is what i do to save the attributes to dictionaries and strings. But the problem is that i am hard-coding the key value 1,2,3 etc.. (ex: [contentDictionary objectForKey:#"2"];)
In reality i don't know how many students will the JSON file have. There might be 100 or even more. So how can i write this in a way where the code will automatically, read JSON response (all 100 records) and save it to NSDictionary and vice versa ?
note: I guess i have to use a for loop or something.
It looks like you have a dictionary in 'contentsOfDictionary' where the keys are "1", "2", ... and the values are dictionaries containing the names/telephone numbers. So you just need to iterate through all the values:
NSMutableArray *studentDictionaries = [[NSMutableArray alloc] init];
for (NSDictionary *studentDictionary in contentOfDictionary.allValues)
{
[studentDictionaries addObject:studentDictionary];
}
If each dictionary entry in your JSON response is uniquely numbered and increasing without gaps, then you could do the following:
NSMutableArray *studentDictionaries = [[NSMutableArray alloc] init];
NSUInteger index = 1;
NSDictionary *studentDictionary;
while (studentDictionary = [contentDictionary objectForKey:[NSString stringWithFormat:#"%d", index++]]) {
[studentDictionaries addObject:studentDictionary];
}
Take a look at NSJSONSerialization available since iOS5 (or SBJSON framework). You'll get your JSON parsed and embedded in obj-c objects.
Instead of using NSDictionary to store responsestring JSONValue
NSDictionary *contentOfDictionary = [responseString JSONValue];
use NSArray to store responsestring JSONValue
NSArray *arr= [responseString JSONValue];
In this way you will get the total count ,each object in the array is a dictionary which can be accessed easily.
Currently I am using the following code to parse the JSON link sent. This is how I also send a GET call to the Google Reader API for an upcoming iPhone application of mine.
- (NSArray *)subscriptionList
{
if(!cookies && [cookies count] == 0) {
[self requestSession];
}
NSString * url = #"http://www.google.com/reader/api/0/subscription/list?output=json&client=scroll";
ASIHTTPRequest * request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
[request setRequestMethod:#"GET"];
[request setRequestCookies:cookies];
[request addRequestHeader:#"Authorization" value:[NSString stringWithFormat:#"GoogleLogin auth=%#", [self auth]]];
[request startSynchronous];
subfeeds = [NSMutableArray array];
// Create new SBJSON parser object
SBJSON *parser = [[SBJSON alloc] init];
if ([request responseStatusCode] == 200) {
NSData * sixty = [request responseData];
NSString * body = [[NSString alloc] initWithData:sixty encoding:NSUTF8StringEncoding];
if (body) {
NSArray *feeds = [parser objectWithString:body error:nil];
NSLog(#"Array Contents: %#", [feeds valueForKey:#"subscriptions"]);
NSLog(#"Array Count: %d", [feeds count]);
NSDictionary *results = [body JSONValue];
NSArray *ohhai = [results valueForKey:#"subscriptions"];
for (NSDictionary *title in ohhai) {
subTitles = [title objectForKey:#"title"];
NSLog(#"title is: %#",subTitles);
}
}
}
return subfeeds;
[subTitles release];
[parser release];
}
I can successfully parse the JSON using the above code, and it successfully outputs the titles into NSLog. In my RootViewController.m, I call the following to grab this -(NSArray *)subscriptionList.
-(void)viewDidAppear:animated {
GoogleReader * reader = [[GoogleReader alloc] init];
[reader setEmail:gUserString];
[reader setPassword:gPassString];
//feedItems is a NSArray where we store the subscriptionList NSArray
feedItems = [reader subscriptionList];
//NSString *feedTitle = [];
NSLog(#"%#", feedItems);
[reader release];
// the rest of the function
}
The code above successfully works with the credentials entered. As you can see there is also a commented NSString called feedTitle. This is where I want to pull the #"title" from the parsed JSON but I do not know how to call it.
Any help would be greatly appreciated!
This is what the JSON source looks like:
{"subscriptions":
[
{"id":"","title":"","categories":[],"sortid":"","firstitemmsec":""},
{"id":"","title":"","categories":[],"sortid":"","firstitemmsec":""},
{"id":"","title":"","categories":[],"sortid":"","firstitemmsec":""},
{"id":"","title":"","categories":[],"sortid":"","firstitemmsec":""},
{"id":"","title":"","categories":[],"sortid":"","firstitemmsec":""}
]
}
I'm interested in only the "title" node.
Well, it would help if you added the source JSON but it's quite easy to grasp how SBJSON parses incoming JSON.
Just an example:
{ "myOutDict" : { "key1": "val1" , "key2" : "val2"} }
This JSON String would be parsed so you can access it by using this code
NSDictionary* myOuterdict = [feeds valueForKey:#"myOutDict"]);
NSString* val1 = [myOuterdict valueForKey:#"key1"]);
NSString* val2 = [myOuterdict valueForKey:#"key2"]);
Edit: Checked my personal Google Reader feed:
The JSON looks like this
{
"subscriptions": [{
"id": "feed/http://adambosworth.net/feed/",
"title": "Adam Bosworth's Weblog",
"categories": [],
"sortid": "0B5B845E",
"firstitemmsec": "1243627042599"
},
{
"id": "feed/http://feeds.feedburner.com/zukunftia2",
"title": "Zukunftia",
"categories": [],
"sortid": "FCABF5D4",
"firstitemmsec": "1266748722471"
}]
}
So the corresponding Objective C Code would be:
NSArray* subscriptions= [feeds valueForKey:#"subscriptions"]);
foreach(NSDictionary* item in subscriptions) {
// Do stuff
// NSString* title = [item valueForKey:#"title"]
// NSString* id = [item valueForKey:#"id"]
}
I'm not sure I understand the question. Are you trying to get a title for the feed as a whole, or per-item? Because I can't see a title property for the subscriptions array in the source JSON.