I am unsure how to parse nested JSON output. I am using Googles JSON geocoding and trying to extract the coordinates. I am thinking I need another level of parsing. My code that does not work:
hostStr = [hostStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *hostURL = [NSURL URLWithString:hostStr];
NSString *jsonString = [[NSString alloc] initWithContentsOfURL:hostURL];
self.jsonArray = [jsonString JSONValue];
NSDictionary *coordinates = [self.jsonArray objectForKey:#"id:p1"];
NSLog(coordinates);
NSString *point = [coordinates objectForKey:#"Point"];
NSLog(point);
The JSON:
{
"name": "11111 WASHINGTON AVE # 116 SAN PEDRO, CA 91111",
"Status": {
"code": 200,
"request": "geocode"
},
"Placemark": [ {
"id": "p1",
"address": "11111 Washington Ave, San Pedro, CA 91111, USA",
"AddressDetails": {
"Accuracy" : 8,
"Country" : {
"AdministrativeArea" : {
"AdministrativeAreaName" : "CA",
"Locality" : {
"LocalityName" : "San Pedro",
"PostalCode" : {
"PostalCodeNumber" : "91111"
},
"Thoroughfare" : {
"ThoroughfareName" : "Washington Ave"
}
}
},
"CountryName" : "USA",
"CountryNameCode" : "US"
}
},
"ExtendedData": {
"LatLonBox": {
"north": 37.7026153,
"south": 37.6999173,
"east": -122.1393925,
"west": -122.1420904
}
},
"Point": {
"coordinates": [ -122.1407313, 50.7012704, 0 ]
}
} ]
}
It looks like you're unclear on how to reach into nested objects in the parsed JSON. I assume you're using JBJson (formerly Json-Framework) to get that JSONValue category on NSString, yes? If so, it's parsed the whole deal, you just have to walk it.
The first helpful this online json visualizer: http://jsonviewer.stack.hu/
Paste your raw JSON into that to see the whole tree structure of it.
Then, you should understand your'e going to to get an NSDictionary that has NSDictionaries and NSArrays in its values. So it's not "id: p1" you're digging into. If you want those coordinates, the coordinates array is at the path Placemark[0].Point.coordinates.
It's going to look more like:
NSArray *placemarks = [self.jsonArray objectForKey:#"Placemark"];
NSDictionary *mark = [placemarks objectAtIndex:0];
NSDictionary *point = [mark objectForKey:#"Point"];
NSArray *coordinates = [point objectForKey:#"coordinates"];
A clever person who has worked in Obj-c more recently than I might be able to walk that with an keypath or something, but I did it this way to show you the nested objects you're really navigating here.
Related
The JSON from the backend is the following
"data": [
{
"id": 108,
"userId": "84945dd7-4ebe-418a-b5ec-bd418d226778",
"notificationType": 0,
"messagingService": 1,
"status": 2
},
{
"id": 109,
"userId": "84945dd7-4ebe-418a-b5ec-bd418d226778",
"notificationType": 0,
"messagingService": 2,
"status": 2
},
{
"id": 110,
"userId": "84945dd7-4ebe-418a-b5ec-bd418d226778",
"notificationType": 1,
"messagingService": 1,
"status": 2
},
{
"id": 111,
"userId": "84945dd7-4ebe-418a-b5ec-bd418d226778",
"notificationType": 1,
"messagingService": 3,
"status": 2
}
]
I fetch the records to an Array from the backend
#property(nonatomic, strong)NSArray *userPreferences;
What I want to succeed is to display those records with the same key "notificationType" in a single cell to present the different types of the other key "messagingService". And finally to tap on any indexPath.row and know which record I have choose and do my active/inactive option.
thank you for the message Jordan Bonitatisfor, based on your example this is what i came up with :
NSMutableDictionary *resultDict = [NSMutableDictionary dictionary];
for (int i = 0; i < [preferences count]; i++)
{
if (resultDict[[preferences[i] valueForKey:#"notificationType"]]) {
//pull out the array and add to it
NSMutableArray *mutableArray = [[NSMutableArray alloc]initWithArray: resultDict[[preferences[i] valueForKey:#"notificationType" ]]];
[mutableArray addObject:preferences[i]];
[resultDict setValue:mutableArray forKey:[preferences[i] valueForKey:#"notificationType" ] ];
}
else
{
NSArray *array = #[preferences[i]];
[resultDict setValue:array forKey:[preferences[i] valueForKey:#"notificationType" ] ];
}
}
[self.foundPreferences addObject:resultDict];
How can i append the resultDict now to the proper cell .
After hard testing and trial and errors i managed to succeed to exactly what i want with the help of Generics (never used them before) thx for all the help.
NSMutableDictionary<NSNumber*, NSMutableDictionary<NSNumber *, KYNotificationPreference *> *> *preferences = [NSMutableDictionary new];
for(NSDictionary *rawPreference in (*response).data){
KYNotificationPreference *preference = [KYDeserializer notificationPreferenceFromSerializedObject:rawPreference];
NSMutableDictionary *notificationTypeDictionary = preferences[#(preference.notificationType)];
if(!notificationTypeDictionary){
notificationTypeDictionary = [NSMutableDictionary new];
[preferences setObject:notificationTypeDictionary forKey:#(preference.notificationType)];
}
[notificationTypeDictionary setObject:preference forKey:#(preference.messagingService)];
}
Anybody got an idea of how to map this response to a mantle object?
I need to get these to an NSArray of custom classes. But the Mantle documentation has no mention on how to do this.
Thanks in advance.
[
[
{
"plu_id": "1744",
"name": "With egg",
"price": "2.00",
"group": null
}
],
[
{
"plu_id": "1745",
"name": "add roast chicken",
"price": "3.00",
"group": "1"
},
{
"plu_id": "1749",
"name": "add beef",
"price": "4.00",
"group": "1"
}
]
]
Please try the below snippet mentioned for an identical issue
+ (NSValueTransformer *)allRowsJSONTransformer
{
return [MTLValueTransformer transformerWithBlock:^id(NSArray *inSectionJSONArray) {
NSMutableArray *sectionArray = [[NSMutableArray alloc] initWithCapacity:inSectionJSONArray.count];
for( NSArray *section in inSectionJSONArray )
{
NSError *error;
NSArray *cardItemArray = [MTLJSONAdapter modelsOfClass:[CKMCardItem class] fromJSONArray:section error:&error];
if( cardItemArray != nil )
{
[sectionArray addObject:cardItemArray];
}
}
return sectionArray;
}];
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have a JSON file that looks like this in my project:
{
"city": [
{
"NewYork": [
{
"url_id": "63",
"title": "someTitle"
},
{
"url_id": "62",
"title": "someOtherTitle"
}
],
"Boston": [
{
"url": "68",
"title": "someTitle"
}
]
.
.
.
Then I'm trying to go through it in Objective-C and create an array of only the names of the cities. I'm able to log the whole JSON, or the properties of "New York", but not just the names.
Is my JSON wrong or am I doing something wrong in the code?
Edit: I forgot to mention that some cities could have multiple id's and titles so I believe creating dictionaries is out of question? Also I have the data in a file so I'm not creating it in the code.
This JSON doesn't seem quite right. The cities value should just be a dictionary:
{
"cities" : {
"Boston" : [
{
"url_id" : "63",
"title" : "someTitle"
},
{
"url_id" : "62",
"title" : "someOtherTitle"
}
],
"New York" : [
{
"url_id" : "63",
"title" : "someTitle"
},
{
"url_id" : "62",
"title" : "someOtherTitle"
}
]
}
}
If you wanted to get the array of city names from the above JSON, you'd convert this to a dictionary and use allKeys of the value returned from the cities key:
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
NSArray *cityNames = [dictionary[#"cities"] allKeys];
Personally, I think it would be better to make your cities value in the JSON an array of dictionaries, where the city name is an attribute of the dictionary:
{
"cities" : [
{
"name" : "New York",
"urls" : [
{
"url_id" : "63",
"title" : "someTitle"
},
{
"url_id" : "62",
"title" : "someOtherTitle"
}
]
},
{
"name" : "Boston",
"urls" : [
{
"url_id" : "63",
"title" : "someTitle"
},
{
"url_id" : "62",
"title" : "someOtherTitle"
}
]
}
]
}
In which case, you'd retrieve the city names like so:
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
NSArray *cityNames = [dictionary[#"cities"] valueForKey:#"name"];
But the JSON proposed in the question seems to have some redundant [, IMHO. And I think the key name of city is misleading because it contains a number of cities, so I'd instead suggest cities.
You must create first a dictionary that contains city key and city key must assign to an array.
NSDictionary *newYorkDict = {
#"url_id":#"63",
#"title":#"someTitle"
};
NSDictionary *bostonDict = {#"url_id":#"63",
#"title":#"someTitle"
};
NSArray *newYorkArray = [newYorkDict];
NSArray *bostonArray = [bostonDict];
NSDictionary *dict = {
#"New york":newYorkArray,
#"Boston":bostonArray
};
NSArray *cityArray = [dict];
NSDictionary *mainDict = {#"city":cityArray};
Can anyone please help me map this json object in restkit 0.20 ?
"feeds" : [
{
"id": 32131354,
"caption": "Blah Blah Blah.",
"story" : "blah blah someone blah blah someone else",
"story_tags": {
"0": [
{
"id": 21231654,
"name": "Someone",
"offset": 0,
"length": 25,
"type": "page"
}
],
"33": [
{
"id": 3213212313,
"name": "Someone else",
"offset": 33,
"length": 12,
"type": "page"
}
]
},
}
{
...
}
]
I would really appreciate any help. This is what am doing right now:
RKEntityMapping *feedsMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([FacebookFeed class]) inManagedObjectStore:managedObjectStore];
feedsMapping.identificationAttributes = #[#"id"];
[feedsMapping addAttributeMappingsFromDictionary:#{
#"caption" : #"caption",
#"id" : #"id",
#"story" : #"story",
}];
and this is for relationship mapping
RKEntityMapping *facebookFeedStoryTagsMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([FacebookFeedStoryTag class]) inManagedObjectStore:managedObjectStore];
facebookFeedStoryTagsMapping.identificationAttributes = #[#"id"];
[facebookFeedStoryTagsMapping addAttributeMappingToKeyOfRepresentationFromAttribute:#"offset"];
[facebookFeedStoryTagsMapping addAttributeMappingsFromDictionary:#{
#"(offset).id" : #"id",
#"(offset).length" : #"length",
#"(offset).name" : #"name",
#"(offset).type" : #"type",
}];
[feedsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"story_tags" toKeyPath:#"story_tags" withMapping:facebookFeedStoryTagsMapping]];
but i am getting the following error:
restkit.object_mapping:RKMappingOperation.m:745 Key path 'story_tags' yielded collection containing another collection rather than a collection of objects: (
(
{
id = 31314654654;
length = 25;
name = "Someone";
offset = 0;
type = page;
}
)
)
The JSON "0": [ presents an issue because we really want a dictionary in there (that is how your mapping is written), but we actually have an array. This is the source and meaning of the error you see.
Ideally you would change the JSON...
As it stands your FacebookFeedStoryTag would need to map the entire array (and the dictionary it contains) into a transformable attribute. This is because the mapping can not handle the nested array.
You could make this transformable attribute a transient and implement a custom setter / willSave method to take the array and extract the dictionary contents. As the key names match this could be simply done using setValuesForKeysWithDictionary: (though you would need to handle the offset key).
I'm creating a web request to pull lng and lat data based on zip (using the following url)
http://maps.google.com/maps/geo?q=50266
Doing so I get back the following json
{
"name": "50266",
"Status": {
"code": 200,
"request": "geocode"
},
"Placemark": [ {
"id": "p1",
"address": "West Des Moines, IA 50266, USA",
"AddressDetails": {
"Accuracy" : 5,
"Country" : {
"AdministrativeArea" : {
"AdministrativeAreaName" : "IA",
"Locality" : {
"LocalityName" : "West Des Moines",
"PostalCode" : {
"PostalCodeNumber" : "50266"
}
}
},
"CountryName" : "USA",
"CountryNameCode" : "US"
}
},
"ExtendedData": {
"LatLonBox": {
"north": 41.6005010,
"south": 41.5254700,
"east": -93.7347000,
"west": -93.8435030
}
},
"Point": {
"coordinates": [ -93.7353858, 41.5998115, 0 ]
}
} ]
}
What I'm trying to pull from this is simply the coordinates section. Here is my current attempt that throws and exception when I hit the last line shown below
//after I get the response I turn it into json and this is working
NSArray* json = [items JSONValue];
NSString* coords = [json objectForKey:#"Placemark.Point.coordinates"];
What I'm I missing here for a quick pull of the coordinates?
The overall value return is not an array, it's a dictionary. Note that the first character is {. If it were an array, it would be [.
NSDictionary * json = [string JSONValue];
Now, you want the stuff under the "Placemarks" key. Note that this returns an array, since the character after the "Placemarks" key (and colon) is a [.
NSArray * placemarks = [json objectForKey:#"Placemark"];
From this array, you want the first element, which is another NSDictionary:
NSDictionary *firstPlacemark = [placemarks objectAtIndex:0];
From this dictionary, you want the dictionary under the key "Point":
NSDictionary *point = [firstPlacemark objectForKey:#"Point"];
From this dictionary, you want the array under the key "coordinates":
NSArray * coordinates = [point objectForKey:#"coordinates"];
At this point, you have the array that contains 3 NSNumber objects. Voilá!
For the advanced user, you can probably use key-value coding to get at it:
NSArray * coordinates = [json valueForKeyPath:#"Placemark[0].Point.coordinates"];
Though I wouldn't recommend that unless you clearly understand what's going on there.
That does not work. Never mind! :)
Keep in mind that "[ -93.7353858, 41.5998115, 0 ]" is not a string