I'm trying to parse this JSON:
{
"GetMachineGroupsResult": {
"MachineGroups": [
{
"GroupCount": 1,
"GroupID": 101,
"GroupName": "Machine11"
},
{
"GroupCount": 6,
"GroupID": 201,
"GroupName": "Machine12"
},
{
"GroupCount": 1,
"GroupID": 301,
"GroupName": "Machine13"
},
{
"GroupCount": 1,
"GroupID": 501,
"GroupName": "Machine14"
},
{
"GroupCount": 7,
"GroupID": 701,
"GroupName": "Machine15"
},
{
"GroupCount": 1,
"GroupID": 901,
"GroupName": "Machine16"
},
{
"GroupCount": 1,
"GroupID": 1001,
"GroupName": "Machine17"
}
],
"Status": 0
}
}
Into an object created with attributes GroupCount, GroupID and GroupName.
Here is my code:
if (request.responseStatusCode >= 200 && request.responseStatusCode < 300)
{
NSData *responseData = [request responseData];
NSError* error;
NSDictionary* jsonOverview = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
NSString *resultStatusString = jsonOverview[#"GetMachineOverviewResult"][#"Status"];
int resultStatus = [resultStatusString intValue];
NSDictionary *parsedObject = jsonOverview[#"GetMachineGroupsResult"];
NSMutableArray *groups = [[NSMutableArray alloc] init];
NSArray *results = [parsedObject valueForKey:#"MachineGroups"];
NSLog(#"Count %lu", (unsigned long)results.count); //results.count = 7
for (NSDictionary *parseDic in results) {
MachineGroupList *machinegrouplist = [[MachineGroupList alloc] init];
NSLog(#"%#", [parseDic class]);
NSLog(#"%#", parseDic);
for (NSString *key in parseDic) {
if ([machinegrouplist respondsToSelector:NSSelectorFromString(key)]) {
[machinegrouplist setValue:[parseDic valueForKey:key] forKey:key];
}
[groups addObject:machinegrouplist];
}
}
NSLog (#"GroupObjects %lu", (unsigned long)[groups count]); //groups count = 21
For some reason, which I cannot fathom, it parses each item three times and I end up with 21 objects instead of 7. I know it will be something simple for one of the experts here but I am new to all this and would really appreciate a helping hand here, thanks.
Edit:
Thanks a lot, here is how it now looks and it works.. The addobject was in the wrong section!
for (NSDictionary *parseDic in results)
{
MachineGroupList *machinegrouplist = [[MachineGroupList alloc] init];
NSLog(#"%#", [parseDic class]);
NSLog(#"%#", parseDic);
for (NSString *key in parseDic)
{
if ([machinegrouplist respondsToSelector:NSSelectorFromString(key)])
{
[machinegrouplist setValue:[parseDic valueForKey:key] forKey:key];
}
//[groups addObject:machinegrouplist];
}
[groups addObject:machinegrouplist];
}
NSLog (#"GroupObjects %lu", (unsigned long)[groups count]); //groups count = 7
What's happening is the following. First, lets comment out some of the last lines of code so that it looks like this:
for (NSDictionary *parseDic in results) {
//MachineGroupList *machinegrouplist = [[MachineGroupList alloc] init];
NSLog(#"%#", [parseDic class]);
//NSLog(#"%#", parseDic);
//for (NSString *key in parseDic) {
// if ([machinegrouplist respondsToSelector:NSSelectorFromString(key)]) {
// [machinegrouplist setValue:[parseDic valueForKey:key] forKey:key];
// }
// [groups addObject:machinegrouplist];
//}
}
//NSLog (#"GroupObjects %lu", (unsigned long)[groups count]); //groups count = 21
You'll se that you're iterating over 7 dictionaries, each of which has 3 objects.
Now, comment out the previous NSLog, uncomment the the inner for loop and add a NSLog inside that loop to see what you're iterating on.
for (NSDictionary *parseDic in results) {
//MachineGroupList *machinegrouplist = [[MachineGroupList alloc] init];
//NSLog(#"%#", [parseDic class]);
//NSLog(#"%#", parseDic);
for (NSString *key in parseDic) {
// if ([machinegrouplist respondsToSelector:NSSelectorFromString(key)]) {
// [machinegrouplist setValue:[parseDic valueForKey:key] forKey:key];
// }
// [groups addObject:machinegrouplist];
NSLog(#"key: %#", key);
}
}
//NSLog (#"GroupObjects %lu", (unsigned long)[groups count]); //groups count = 21
You are iterating over the 3 objects of each of the 7 dictionaries and since you're adding each object to groups outside of if ([machinegrouplist respondsToSelector:NSSelectorFromString(key)]) you end up adding 21 to groups
Cheers.
Related
I have a problem to communicate with a server. The webserver expects all parameters in the JSON object to be a string. So every number and every boolean in every container needs to be a string.
For my example I have a NSDictionary full of key values (values are all kinds of types - numbers, arrays etc.). For example:
{
"AnExampleNumber":7e062fa,
"AnExampleBoolean":0,
"AnExampleArrayOfNumber":[17,4,8]
}
Has to become:
{
"AnExampleNumber":"7e062fa",
"AnExampleBoolean":"0",
"AnExampleArrayOfNumber":["17","4","8"]
}
I tried the standard NSJSONSerializer but it doesn't give me any option to do what I need. I then tried to transform everything in the dictionary manually to be a string but that seems to be overhead. Does anyone have hint for me? Maybe a serializer that does just that or a function to convert any objects in a container to strings?
This is one way you could do it. It's non-optimized and has no error handling. It only supports the kinds of objects that NSJSONSerializer supports.
#import <Foundation/Foundation.h>
#interface NSObject(SPWKStringify)
- (id)spwk_stringify;
#end
#implementation NSObject(SPWKStringify)
- (id)spwk_stringify
{
if ([self isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict = (NSDictionary *)self;
NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init];
for (NSString *key in [dict allKeys]) {
newDict[key] = [dict[key] spwk_stringify];
}
return newDict;
} else if ([self isKindOfClass:[NSArray class]]) {
NSMutableArray *newArray = [[NSMutableArray alloc] init];
for (id value in ((NSArray *)self)) {
[newArray addObject:[value spwk_stringify]];
}
return newArray;
} else if (self == [NSNull null]) {
return #"null"; // representing null as a string doesn't make much sense
} else if ([self isKindOfClass:[NSString class]]) {
return self;
} else if ([self isKindOfClass:[NSNumber class]]) {
return [((NSNumber *)self) stringValue];
}
return nil;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSDictionary *dict = #{
#"AnExampleNumber": #1234567,
#"AnExampleBoolean": #NO,
#"AnExampleNull": [NSNull null],
#"AnExampleArrayOfNumber": #[#17, #4, #8],
#"AnExampleDictionary": #{#"innerKey": #[#55, #{#"anotherDict": #[#"foo", #[#1, #2, #"three"]]}]}
};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[dict spwk_stringify] options:NSJSONWritingPrettyPrinted error:NULL];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"result: %#", jsonString);
}
}
The output will be:
result: {
"AnExampleNumber" : "1234567",
"AnExampleNull" : "null",
"AnExampleDictionary" : {
"innerKey" : [
"55",
{
"anotherDict" : [
"foo",
[
"1",
"2",
"three"
]
]
}
]
},
"AnExampleBoolean" : "0",
"AnExampleArrayOfNumber" : [
"17",
"4",
"8"
]
}
Note: Please keep in mind that turning [NSNull null] into a string doesn't make any sense and might actually be misleading and dangerous.
Enjoy.
(I assume you mean NSJSONSerializer, not NSSerializer.)
I doubt you'll find a pre-rolled solution to this. It's not a general problem. As you note, this is incorrect JSON, so JSON serializers shouldn't do it.
The best solution IMO is just write the code to transform your NSDictionary into another NSDictionary that is in the form you want. If you really want to make it a generic solution, I suspect that a custom NSDictionary walker with isKindOfClass: is your best bet. Something like this should work:
NSDictionary *myStringDictForDict(NSDictionary *dict); // forward decl if needed
NSArray *myStringArrayForArray(NSArray *array) {
NSMutableArray *result = [NSMutableArray new];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[NSArray class]]) {
[result addObject:myStringArrayForArray(obj)];
} else if ([obj isKindOfClass:[NSDictionary class]]) {
[result addObject:myStringDictForDict(obj)];
} else {
[result addObject:[obj description]];
}
}];
return result;
}
NSDictionary *myStringDictForDict(NSDictionary *dict) {
NSMutableDictionary *result = [NSMutableDictionary new];
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSArray class]]) {
result[key] = myStringArrayForArray(obj);
} else if ([obj isKindOfClass:[NSDictionary class]]) {
result[key] = myStringDictForDict(obj);
} else {
result[key] = [obj description];
}
}];
return result;
}
I have dictionary:
{
6 = (
{
id = 6;
name = Andrea;
},
{
id = 6;
name = Paolo;
}
);
8 = (
{
id = 8;
name = Maria;
}
);
67 = (
{
id = 67;
name = Francesco;
},
{
id = 67;
name = Sara;
}
);
}
I tried to get Values to array.
My code is:
NSArray *arrayNew= [result valueForKey:#"67"];
NSLog(#"Hello:%#",arrayNew);
But Always i got null value.
My complete code:
NSMutableArray *idArray=[[NSMutableArray alloc]init];
NSString* path = [[NSBundle mainBundle] pathForResource:#"File"
ofType:#"txt"];
NSString* content = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:NULL];
NSMutableData *results11 = [content JSONValue];
NSLog(#"Check:%#",results11);
NSArray *array= [results11 valueForKeyPath:#"field"];
NSMutableDictionary* result = [NSMutableDictionary dictionary];
for (NSDictionary* dict in array)
{
NSNumber* anID = [dict objectForKey:#"id"];
if (![idArray containsObject:[dict objectForKey:#"id"]]) {
// do something
[idArray addObject:[dict objectForKey:#"id"]];
}
NSMutableArray* resultsForID = [result objectForKey:anID];
if (!resultsForID)
{
resultsForID = [NSMutableArray array];
[result setObject:resultsForID forKey:anID];
}
[resultsForID addObject:dict];
}
NSLog(#"Result:%#",result);
NSLog(#"ID arr:%#",idArray);
// NSArray *temp= [results11 valueForKeyPath:#"Response.alertHistory"];
NSString *arrayNew= [result valueForKeyPath:#"67"];
NSLog(#"Hello:%#",arrayNew);
File.txt : {
"field": [
{
"id": 6,
"name": "Andrea"
},
{
"id": 67,
"name": "Francesco"
},
{
"id": 8,
"name": "Maria"
},
{
"id": 6,
"name": "Paolo"
},
{
"id": 67,
"name": "Sara"
}
]
}
Finally with reference of Tommy's solution I solved my issue.
NSArray *commentArray = result[#67];
And my final code:
NSMutableArray *idArray=[[NSMutableArray alloc]init];
NSString* path = [[NSBundle mainBundle] pathForResource:#"File"
ofType:#"txt"];
NSString* content = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:NULL];
NSMutableData *results11 = [content JSONValue];
NSLog(#"Check:%#",results11);
NSArray *array= [results11 valueForKeyPath:#"field"];
NSMutableDictionary* result = [NSMutableDictionary dictionary];
for (NSDictionary* dict in array)
{
NSNumber* anID = [dict objectForKey:#"id"];
if (![idArray containsObject:[dict objectForKey:#"id"]]) {
// do something
[idArray addObject:[dict objectForKey:#"id"]];
}
NSMutableArray* resultsForID = [result objectForKey:anID];
if (!resultsForID)
{
resultsForID = [NSMutableArray array];
[result setObject:resultsForID forKey:anID];
}
[resultsForID addObject:dict];
}
NSLog(#"Result:%#",result);
NSMutableArray *arrayNew = [[NSMutableArray alloc] init];
for (int i=0; i<[idArray count]; i++) {
NSArray *commentArray = result[idArray[i]];
NSLog(#"COMM:%#",commentArray);
NSMutableArray *arr=[[NSMutableArray alloc]init];
for (NSDictionary* dict in commentArray)
{
[arr addObject:[dict objectForKey:#"name"]];
}
[arrayNew addObject:arr];
}
NSLog(#"ID arr:%#",idArray);
NSLog(#"Name arr:%#",arrayNew);
File.txt :
{
"field": [
{
"id": 6,
"name": "Andrea"
},
{
"id": 67,
"name": "Francesco"
},
{
"id": 8,
"name": "Maria"
},
{
"id": 6,
"name": "Paolo"
},
{
"id": 67,
"name": "Sara"
}
]
}
My final result:
ID arr:(
6,
67,
8
)
Name arr:(
(
Andrea,
Paolo
),
(
Francesco,
Sara
),
(
Maria
)
)
The most likely reason for this is that your NSDictionary uses integers, not NSStrings, as its keys. In this case this should work:
NSArray *arrayNew= [result objectForKey:#67]; // No quotes
NSMutableArray *arrayNew = [[NSMutableArray alloc] init];
NSArray *commentArray = [dictionary valueForKey:#"67"];
for (NSDictionary *commentDic in commentArray) {
Model *modelObj = [[Model alloc] init];
modelObj = [Model modelFromDictionary:commentDic];
[arrayNew addObject:modelObj]
}
Also you will have to create Model .h and .m class to do the mapping.
and modelFromDictionary method will do the mapping.
.m
#implementation Version
- (NSDictionary *)jsonMapping {
return [[NSDictionary alloc] initWithObjectsAndKeys:
#"id",#"id",
#"name",#"name",
nil];
}
+ (Model *)modelFromDictionary:(NSDictionary *)dictionary {
Model *model = [[Model alloc] init];
NSDictionary *mapping = [model jsonMapping];
for(NSString *attribute in [mapping allKeys]) {
NSString *classProperty = [mapping objectForKey:attribute];
NSString *attributeValue = [dictionary objectForKey:attribute];
if(attributeValue != nil && ![attributeValue isKindOfClass:[NSNull class]]) {
[model setValue:attributeValue
forKey:classProperty];
}
}
return model;
}
.h
#property (nonatomic, strong) NSString *id;
#property (nonatomic, strong) NSString *name;
+ (Model *)modelFromDictionary:(NSDictionary *)dictionary;
I have a json response below and need to sort the array depending on the 'order' key and show it to the subView.
[
{
"ProjectID": 1,
"SLNO": 1,
"ID": 1,
"Type": "Text",
"Name": "First Name",
"Order": 1,
"Flag": "F"
},
{
"ProjectID": 1,
"SLNO": 3,
"ID": 2,
"Type": "Text",
"Name": "Company",
"Order": 5,
"Flag": "F"
},
{
"ProjectID": 1,
"SLNO": 4,
"ID": 4,
"Type": "Text",
"Name": "Personal Email",
"Order": 3,
"Flag": "F"
},
{
"ProjectID": 1,
"SLNO": 2,
"ID": 8,
"Type": "Text",
"Name": "Last Name",
"Order": 2,
"Flag": "F"
}
]
I read this documentation but how will store and sort the 'tempArray' to the custom class 'SaveAsking' in my following code. I am aware I need to use initWithKey:#"Order", but how in the following case?
NSData *jsonData = [json dataUsingEncoding:NSASCIIStringEncoding];
NSArray *myJsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:Nil];
//NSArray *arrayLabel = [[NSArray alloc] initWithObjects:label1, label2, label3, label4, label5, label6, nil];
NSMutableArray *arrayOrder = [NSMutableArray arrayWithCapacity:myJsonArray.count];
NSMutableArray *arrayName = [NSMutableArray arrayWithCapacity:myJsonArray.count];
i = 0;
for(NSDictionary *myJsonDictionary in myJsonArray)
{
//UILabel *label = (UILabel *)[arrayLabel objectAtIndex:i++];
//[label setText:myJsonDictionary[#"Name"]];
NSString *name = myJsonDictionary[#"Name"];
NSLog(#"Question from ws2 is %#", name);
projectIdGobal = myJsonDictionary[#"ProjectID"];
NSLog(#"Project id from ws2 is %#", projectIdGobal);
slno = myJsonDictionary[#"SLNO"];
NSLog(#"slno from ws2 is %#", slno);
NSString *idWS2 = myJsonDictionary[#"ID"];
NSLog(#"id from ws2 is %#", idWS2);
order = myJsonDictionary[#"Order"];
NSLog(#"order from ws2 is %#", order);
flag = myJsonDictionary[#"Flag"];
NSLog(#"flag from ws2 is %#", flag);
[self putLabelsInScrollView:name:order]; //need to call this method depending on the sorted 'order' key
SaveAsking *save = [[SaveAsking alloc] initWithslno:slno withOrder:order withFlag:flag];
save.slno = slno;
save.order = order;
save.flag = flag;
[temporaryArray addObject:save];
//temporaryArray = [[NSMutableArray alloc] initWithObjects:slno, order, flag, nil];
[arrayOrder addObject:order];
[arrayName addObject:name];
i++;
}
//Sort array or orders
sortedArrayOfOrder = [arrayOrder sortedArrayUsingComparator:^(id str1, id str2) {
if ([str1 integerValue] > [str2 integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
if ([str1 integerValue] < [str2 integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
NSLog(#"Array or orders = %#", arrayOrder);
NSLog(#"Sorted array of orders = %#", sortedArrayOfOrder);
//NSLog(#"Array from ws2 = %#", temporaryArray);
NSLog(#"Array in myJsonArray = %#", myJsonArray);
NSLog(#"Number of cycles in for-each = %d", i);
}
I think you can directly sort myJsonArray by sortUsingComparator on the json object.
So
NSData *jsonData = [json dataUsingEncoding:NSASCIIStringEncoding];
NSArray *myJsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:Nil];
NSArray sortedArrayOfOrder = [arrayOrder sortedArrayUsingComparator:^(NSDictionary json1, NSDictionary json2) {
if ([[json1 objectForKey:#"Order"] integerValue] > [[json2 objectForKey:#"Order"] integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
if ([[json1 objectForKey:#"Order"] integerValue] < [[json2 objectForKey:#"Order"] integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
I'm still trying (I already asked a few question about this) to parse my own JSON file. Here is my JSON :
{
"album":[
{
"album_titre":"Publicité",
"album_photo":"blabla.jpg",
"album_videos":[
{
"titre_video":"Chauffage Compris",
"duree_video":"01'25''",
"photo_video":"chauffage.jpg",
"lien_video":"www.bkjas.jhas.kajs"
},
{
"titre_video":"NIFFF 2012",
"duree_video":"01'43''",
"photo_video":"nifff.jpg",
"lien_video":"www.bkjas.jhas.kajs"
}
]
},
{
"album_titre":"Events",
"album_photo":"bloublou.jpg",
"album_videos":[
{
"titre_video":"Auvernier Jazz",
"duree_video":"01'15''",
"photo_video":"auvernier.jpg",
"lien_video":"www.bkjas.jhas.kajs"
},
{
"titre_video":"NIFFF 2011",
"duree_video":"01'03''",
"photo_video":"nifff2011.jpg",
"lien_video":"www.bkjas.jhas.kajs"
}
]
}
]
}
With help of community, I've made this :
- (void) viewDidLoad
{
[super viewDidLoad];
dispatch_async (kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:lienAlbumsVideo];
[self performSelectorOnMainThread:#selector(fetchedData:)withObject:data waitUntilDone:YES];
});
}
- (void)fetchedData:(NSData *)responseData {
NSError* error;
NSDictionary *document = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
if (document==nil)
{
NSLog( #"oops\n%#", error);
}
NSArray *album = document[#"album"];
NSMutableArray *album_titre = [NSMutableArray new];
NSMutableArray *album_photo = [NSMutableArray new];
NSMutableArray *album_videos = [NSMutableArray new];
for( NSDictionary *elementOnRoot in album )
{
[album_titre addObject:elementOnRoot[#"album_titre"]];
[album_photo addObject:elementOnRoot[#"album_photo"]];
[album_videos addObject:elementOnRoot[#"album_videos"]];
}
NSLog(#"%#", [album_titre objectAtIndex:0]);
NSLog(#"%#", [album_videos objectAtIndex:1]);
NSLog(#"%#", album_photo);
}
Now, I'm a bit mixed up with structure. My question is how (using my actual Xcode) can I have a list (NSArray or dictionary) of "titre_video", "duree_video", "photo_video" and "lien_video"?
Thank you for your help and sorry for my basic xcode level...
Nicolas
for( NSDictionary *albumDic in album )
{
for( NSDictionary *album_videosDic in albumDic[#"album_videos"])
{
[album_titre addObject:album_videosDic[#"titre_video"]];
[album_videos addObject:album_videosDic[#"duree_video"]];
[album_photo addObject:album_videosDic[#"photo_video"]];
}
}
How can I loop through this part of the json [{first set of values},{data->children->data->body} in objective c?
Json is
[
{
"kind": "Listing"
},
{
"kind": "Listing",
"data": {
"children": [
{
"data": {
"body": "body1"
}
},
{
"data": {
"body": "body2"
}
}
]
}
}
]
My current code is
m_ArrList=[[NSMutableArray alloc]init];
NSDictionary *infomation = [self dictionaryWithContentsOfJSONString:#"surveyquestion.json"];
NSArray *array=[infomation objectForKey:#"data"];
int ndx;
NSLog(#"%#",array);
for (ndx = 0; ndx < [array count]; ndx++) {
NSDictionary *stream = (NSDictionary *)[array objectAtIndex:ndx];
NSArray *string=[stream valueForKey:#"children"];
//i am stuck here
}
What do I do at the "//i am stuck here" ?
You might need to add the values of #"children" dictionary in an array and then parse that array to get the data inside children
[childrenArray addObject:[stream objectForKey:#"children"]];
// finally parse childrenArray
// You Just need to Implement following Lines and you will get all the data for Key Body in children array
NSDictionary *infomation = [self dictionaryWithContentsOfJSONString:#"surveyquestion.json"];
NSArray *string= [[infomation objectForKey:#"data"] objectForKey:#"children"];
[string enumerateObjectsUsingBlock:^(id obj, NSUInteger ind, BOOL *stop){
NSLog(#"Body : %#",[[obj objectForKey:#"data"] objectForKey:#"body"]);
}];
Using NSJSONSerialization try to implement this. Here you need to pass NSString as jsonStr which you need to read from your file.
NSError *jsonError = nil;
id allValues = [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:&jsonError];
if(jsonError!=nil)
NSLog(#"Json_Err: %#",jsonError);
NSArray *array=allValues;
for (int ndx = 0; ndx < [array count]; ndx++) {
NSDictionary *stream = (NSDictionary *)[array objectAtIndex:ndx];
NSLog(#"%#",[stream objectForKey:#"kind"]);
NSArray *child = [[stream objectForKey:#"data"] objectForKey:#"children"];
//i am stuck here
for(int i =0; i <[child count];i++)
{
NSDictionary *childData = (NSDictionary *)[child objectAtIndex:i];
//NSLog(#"%#",[childData objectForKey:#"data"]);
NSLog(#"%#",[[childData objectForKey:#"data"] objectForKey:#"body"]);
}
}