How to parse a Nested JSON - ios

Thank you reading my post, I known this topic was asked so many time, and I had saw that but no luck...
I want to parse a simple JSON string, as followings:
[
{
"id":"1",
"name_en":"Photography",
"subchannels":[
{
"id":"4",
"name_en":"John"
},
{
"id":"18",
"name_en":"Sam"
}
]
},
{
"id":"7",
"name_en":"Equipment",
"subchannels":[
{
"id":"25",
"name_en":"ABC Company"
},
{
"id":"40",
"name_en":"CDE Company"
}
]
}
]
It had convert this string to NSDictionary
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *testDic = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&e];
Then I list the Dictionary Key
for(id key in testDic) {
NSLog(#"%#", key);
}
The result is the entire record as the Dictionary Key, so I can't use [testDic objectForKey:key] to retrieve the value.
How can I get the first row name_en and the second row subchannels value?
(is it possible to retrieve easily like xpath in XML?)
Thank you for helping.

First of all. The root object of your model is NSArray object - not `NSDictionary. '[]' means array and {} means dictionary.
NSArray *dataArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&e];
for (NSDictionary *entry in dataArray) {
NSString *name = entry[#"name_en"];
NSArray *subchannels = entry[#"subchannels"]; //array of dictionaries
NSLog(#"Name %s", name);
for (NSDictionary *subchannel in subchannels) {
NSLog(#"Subchannels name %# id: %d", subchannel[#"name"], [subchannel[#"id"] integerValue]);
}
}
If you want to perform advances JSON parsing I encourage you to look at Mantle github project.

Related

Single object json parse - what am I doing wrong?

This has got to be something obvious that I am doing wrong. I have been banging my head against a wall trying to figure out what is going on. I already have this json parsing done in the android version of my app, now trying to parse this simple json in xcode and can't get it done.
NSError *myError = nil;
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:&myError];
NSLog([res objectForKey:#"Date"]);
This code get me the "unrecognized selector sent to instance" error.
Here is the json data and you can see Date is one of the objects:
[{"Date":"2016-06-17T22:56:33.0811255-05:00"}]
Thanks in advance for any help on this issue. I've tried to simplify this post, but if more info is needed I will try and quickly provide.
http://i.stack.imgur.com/Y5fsT.png
JSONObjectWithData is returning an array of dictionaries and not a dictionary. Your print out of the raw JSON confirms this:
[{"Date":"2016-06-17T22:56:33.0811255-05:00"}] // This is an array
However you're attempting to treat that response object like a dictionary. In doing so you're calling a dictionary method (objectForKey:) on an array. This results in a crash. Try something like this:
NSError *error = nil;
id responseObject = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:&error];
if (error)
{
// Handle error
return;
}
NSLog(#"%#", responseObject);
if ([responseObject isKindOfClass:[NSArray class]])
{
NSArray *responseArray = (NSArray *)responseObject;
for (id item in responseArray)
{
NSLog(#"%#", item);
if ([item isKindOfClass:[NSDictionary class]])
{
NSDictionary *dictionary = (NSDictionary *)item;
NSString *dateString = [dictionary objectForKey:#"Date"];
NSLog(#"%#", dateString);
}
}
}
else
{
// responseObject is not an array...
}
I'm pretty sure this is because you should first set res as [NSDictionary]. Then pick the first element in that array and then get objectForKey: "Date". Normal JSON Data starts with a {, this starts with a [. Which means it's an array.
You can see it for yourself in the screenshot when it says #: 1 Element . THEN it says 1 key/value pair. The NSDictionary is inside an array.NSError
Try this code:
*myError = nil;
[NSDictionary] *res = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:&myError];
if (res.count > 0) {
NSLog([res[0] objectForKey:#"Date"]);
}

JSON parsing error in Objective-C

I am trying to parse this JSON in Objective-C. The response object looks thus:
(
{
"Year": "2003",
"SumOfYear": "0.20"
},
{
"Year": "2004",
"SumOfYear": "0.64"
},
{
"Year": "2005",
"SumOfYear": "0.90"
}
)
I tried the following
NSDictionary* dictionaryObtained = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
NSLog(#"dict = %#",dictionaryObtained);
NSDictionary *yearsObtained = [dictionaryObtained objectForKey:#"Year"];
But I obtain the following error:
-[__NSCFArray bytes]: unrecognized selector sent to instance 0x18a3bfd0
Where am I going wrong?
I want to obtain all the Year in a NSArray and all the SumOfYear in another NSArray.
The error is from this line
NSDictionary* dictionaryObtained = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
It appears (hard to tell for sure without better info from you) that responseObject has already been parsed from JSON string into Objective-C objects. Therefore you should not run it through NSJSONSerialization again.
But what you have is an NSArray, so, assuming you want to collect an array of the "Year" values, you need something along the lines of:
NSMutableArray* yearsObtained = [NSMutableArray array];
for (NSDictionary* dictionaryObtained in responseObject) {
NSLog(#"dict = %#",dictionaryObtained);
NSString* year = [dictionaryObtained objectForKey:#"Year"];
NSLog(#"year = %#", year);
[yearsObtained addObject:year];
}
You have wrong(right format - but not to match your code) the json.
If you want your code to work this is the correct:
{ "Year":
[
{
"Year": "2003",
"SumOfYear": "0.20"
},
{
"Year": "2004",
"SumOfYear": "0.64"
},
{
"Year": "2005",
"SumOfYear": "0.90"
}
]
}
Your json as it is can be parsed:
for(NSDictionary *myDict in jsonObj){
NSString *year = [myDict objectForKey:#"Year"];
}
I would suggest to do it like that:
NSArray * dataArray = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil];
for(NSDictionary * diction in dataArray)
{
NSLog(#"%#",[diction objectForKey:#"Year"]);
}
because you have an array of dictionaries you should put a JSONSerialization inside an NSArray
then to go inside it with dictionary thus u can get to your years as you wish.
From comments below it seems like your responseObject is already parsed
so you can just go
for(NSDictionary* dict in responseObject)
{
NSLog(#"%#",[dict objectForKey:#"Year"]);
}
The simplest way to parse your JSON and get two arrays is
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil];
NSArray *years = [jsonArray valueForKeyPath:#"Year"];
NSArray *sums = [jsonArray valueForKeyPath:#"SumOfYear"];
KVC is a great instrument for parsing data structures.

Parsing JSON dictionary with multiple arrays with NSJSONSerialization does not result in NSDictionary or NSArray

I am trying to parse a JSON dictionary in the form of:
{
"bible": {
"book": [
{
"bookName": "Genesis",
"chapter": [
{
"chapterNum": "1",
"verse": [
{
"verse": "In the beginning God created the heaven and the earth.",
"verseNum": "1"
},
{
"verse": "And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.",
"verseNum": "2"
},
I am having difficulties getting to the proper data within this structure. My goal is to create a Verse managed object that has a verseNum, verse (the text), chapterNum, and bookName properties.
I need help creating the object. Currently, when I create the NSDictionary using NSJSONSerialization, I only obtain one dictionary, with a single NSCFString:
NSError* err = nil;
NSString* dataPath = [[NSBundle mainBundle] pathForResource:#"kjv"
ofType:#"json"];
NSDictionary *bible = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath]
options:kNilOptions
error:&err];
for (NSDictionary *book in [bible valueForKey:#"bible"]) {
NSLog(#"%#", book);
}
The console output simply reads: book
Try the following code:
NSError *error = nil;
id JSONResponse = [NSJSONSerialization JSONObjectWithData:self.responseData
options:0
error:&error];
if (error) {
NSLog(#"JSON Error: %#", error);
return;
}
// Should be an NSDictionary or NSArray
NSLog(#"JSON response: %#", [JSONResponse description]);
NSArray *books = [JSONResponse valueForKeyPath:#"bible.book"];
for (NSDictionary *book in books) {
NSLog(#"%#", book);
NSString *bookName = [book valueForKey:#"bookName"];
NSArray *chapters = [book valueForKey:#"chapter"];
// loop through the chapters
...
NSArray *verses = [book valueForKey:#"verse"];
// loop through the verses
...
}
Seems your JSON document is an object (dictionary), containing one element named "bible". bible is itself a dictionary containing one element named "book". book is an array. The array elements are objects, with an item "bookName" containing a string, and another item "chapter" containing an array and so on. So:
NSDictionary* JSONResponse = ...
NSAssert ([JSONResponse isKindOfClass:[NSDictionary class]]);
NSDictionary* bible = JSONResponse [#"bible"];
NSAssert ([bible isKindOfClass:[NSDictionary class]]);
NSArray* books = bible [#"book"];
NSAssert ([books isKindOfClass:[NSArray class]]);
for (NSDictionary* book in books)
{
NSAssert ([book isKindOfClass:[NSDictionary class]]);
NSString* bookName = book [#"bookName"];
NSArray* chapters = book [#"chapter"];
}
and so on.

filter Subdata's in JSON data in IOS

I am new to iOS & JSON parsing I'm Getting some JSON data like,
[
{
"id":3,
"name":"SCORM 0",
"visible":1,
"summary":"",
"summaryformat":1,
"modules":[
{
"id":1,
"url":"http:\/view.php?id=1",
"name":"Course01",
"visible":1,
"modicon":"http:\theme\/image.php\/standard\/scorm\/1378190687\/icon",
"modname":"scorm",
"modplural":"SCORM packages",
"indent":0
},
{
"id":2,
"url":"http:\/\/192.168.4.196\/moodle\/mod\/forum\/view.php?id=2",
"name":"News forum",
"visible":1,
"modicon":"http:\//image.php\/standard\/forum\/1378190687\/icon",
"modname":"settle",
"modplural":"Forums",
"indent":0
}
]
},
{
"id":2,
"url":"http:\/\/view.php?id=2",
"name":"News forum",
"visible":1,
"modicon":"http:\/\theme\/image.php\/standard\/forum\/1378190687\/icon",
"modname":"forum",
"modplural":"Forums",
"indent":0
}
]
I need to separate the data's with respect to "modname" != "forum" and store the respective data's in the array.
Helps and Solutions will be appreciated.
NSMutableArray *jsonArray = [[NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e] mutableCopy];
jsonArray = [jsonArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return ![evaluatedObject[#"modname"] isEqualToString:#"forum"];
}];
This is a sketch of what you could do
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error: &error];
NSLog(#"%#",json);
NSLog(#"%#",delegate.firstArray);
NSArray * responseArr = json[#"Deviceinfo"];
for(NSDictionary * dict in responseArr)
{
[delegate.firstArray addObject:[dict valueForKey:#"id"]];
[delegate.secondArray addObject:[dict valueForKey:#"name"]];
[delegate.thirdArray addObject:[dict valueForKey:#"visible"]];
[delegate.fourthArray addObject:[dict valueForKey:#"summery"]];
}
here all data arrange as per your key

NSJSONSerialization - Core Data relationships to JSON

I've been trying to create a class to allow me to output core data out to JSON.
I have managed to get it working to a point, however I seem to have hit a brick wall on a outputting relationships
NSMutableArray * objectsArray = [[NSMutableArray alloc] init];
for (NSManagedObject * object in array) {
if([NSJSONSerialization isValidJSONObject:object]) {
[objectsArray addObject:object];
} else {
NSMutableDictionary *fields = [NSMutableDictionary dictionary];
for (NSAttributeDescription *attribute in [[object entity] properties]) {
NSString *attributeName = attribute.name;
id attributeValue = [object valueForKey:attributeName];
if([results length] > 0)
{
NSArray *chunks2 = [results componentsSeparatedByString: #","];
for (NSString * string in chunks2) {
if([string.lowercaseString isEqualToString:attributeName.lowercaseString])
{
[fields setObject:[NSString stringWithFormat:#"%#",attributeValue] forKey:attributeName];
break;
}
}
}
else
{
if (attributeValue) {
[fields setObject:[NSString stringWithFormat:#"%#",attributeValue] forKey:attributeName];
}
}
}
[objectsArray addObject:fields];
}
}
NSError *error;
NSData * JSONData = [NSJSONSerialization dataWithJSONObject:objectsArray options:kNilOptions error:&error];
And this outputs data fine aslong as I do not have a relationship for example a one -> many or many -> one
It outputs the following
{
"mySegmentation": "(null)",
"number": "9452062"
},
{
"mySegmentation": "<NSManagedObject: 0x212050b0> (entity: SegmentationCodes; id: 0x212090b0 <x-coredata://BEC52F5F-EA26-4CFF-BCCB-09DA163F465D/SegmentationCodes/p13> ; data: <fault>)",
"number": "9448502"
},
How can I get it to also indent in and output the information from the relationship?
I have been scratching my head for a while on this and would appreciate the help
Thanks Matt
From the documentation:
An object that may be converted to JSON must have the following properties:
The top level object is an NSArray or NSDictionary.
All objects are instances of NSString, NSNumber, NSArray,
NSDictionary, or NSNull.
All dictionary keys are instances of NSString.
Numbers are not NaN or infinity.
So, what you have to do is compose a dictionary or array with dictionaries, arrays, strings, numbers, nulls.
Normally relationships in CoreData are not sorted, so NSSets, you have to generate a NSArray from the set (therefor a nice method from Apple exists) and put it as value in the dictionary for the specific key.
Then run - dataWithJSONObject:options:error: for example (as you did before) and retrieve the correct JSON.
Not sure if the indention is right. You have to check that out.
Thats it, hopefully

Resources