I parse a XML file, and after parsing get a NSDictionary object (XMLDictionary named). I'm parsing this:
<result><node><id>27</id><name>Name 1</name><type>0</type><price>0</price><img>/upload/iblock/1a1/1a138b2d4da6e42398beeb21acc8e84f.png</img></node><node><id>28</id><name>Name 2</name><type>0</type><price>0</price><img>/upload/iblock/b72/b724d1550f93987a73b04974b5f7390e.png</img></node></result>
After that i'm trying this (titleArr - NSArray):
_titleArr = [[[[_xmlDictionary objectForKey:#"result"] objectForKey:#"node"] objectForKey:#"name"] valueForKey:#"text"];
In Run-time I get this error in the above line: "Thread 1: signal SIGABRT". How can i fix this problem?
NSError* parseError = nil;
_xmlDictionary = [XMLReader dictionaryForXMLString:myXMLString error:&parseError];
if (parseError != nil) {
NSLog(#"Error on XML parse: %#", parseError);
}
NSLog(#"The full dictionary is %#", _xmlDictionary);
NSDictionary* result = [_xmlDictionary objectForKey:#"result"];
NSLog(#"'result' = %#", result);
NSDictionary* node = [result objectForKey:#"node"];
NSLog(#"'node' = %#", node);
NSString* name = [node objectForKey:#"name"];
NSLog(#"'name' = %#", name);
At the very least, if it fails, the error will be isolated to a single operation. And the NSLogs will show you the values after each step.
Try this:
NSArray *arrResult = [_xmlDictionary objectForKey:#"result"];
for(int i = 0; i < [arrResult count]; i++)
{
NSArray *arrNode = [arrResult objectAtIndex:i] valueForKey:#"node"];
NSString *sName = [arrNode valueForKey:#"Name"];
NSLog(#"Name : %#",sName);
}
Edited Answer
NSArray *arrResult = [_xmlDictionary valueForKey:#"result"];
for (int i = 0; i < [arrResult count]; i++) {
NSDictionary *dicNode = [[arrResult objectAtIndex:i] valueForKey:#"Node"];
NSString *sName = [dicNode valueForKey:#"Name"];
NSLog(#"Name : %#",sName);
}
Related
here is my code. I used NSDictionary and coded to print my json data in my console.but i got error like this:
'NSInvalidArgumentException', reason: '-[__NSCFString objectForKeyedSubscript:]: unrecognized selector sent to instance 0x7c971930'
My code:
if(buttonIndex == 0) {
NSLog(#"OK Button is clicked");
}
else if(buttonIndex == 1) {
if([[textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length]!=0)
{
if(!self.note)
{
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Notes" inManagedObjectContext:context];
NSLog(#"%#",textView.text);
[newNote setValue:textView.text forKey:#"note"];
if([textView.text length]>30)
{
[newNote setValue:[NSString stringWithFormat:#"%#...",[textView.text substringToIndex:25]] forKey:#"title"];
}
else
[newNote setValue:textView.text forKey:#"title"];
[newNote setValue:[NSDate date] forKey:#"mod_time"];
//[newDevice setValue:self.versionTextField.text forKey:#"version"];
//[newDevice setValue:self.companyTextField.text forKey:#"company"];
How to overcome this problem to work and to print my data in my console
Help me out. I am struggling for 2 hours.I googled and change all change.But cant get data in my console. Thanks in advance
I guess you can get data like below this
NSDictionary *monday = jsonResults[#"original"];
NSArray * arrFile = monday[#"files"];
for (NSDictionary *theCourse in arrFile)
{
....
}
Did you checked that received data (i.e., returnData) from sendSynchronousRequest: is returning a plain data?
If the data received is in Base64, you might have to decode this NSData to plain data, and then go ahead with String conversion.
NSData *decodedData = [[NSData alloc] initWithBase64EncodedData:responseData options:NSDataBase64DecodingIgnoreUnknownCharacters];
NSString *str = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
// convert Json to NSDictionary
NSDictionary *jsonResults = [NSJSONSerialization JSONObjectWithData:returnData options:NSJSONReadingMutableContainers error:nil];
// NSLog(#"%#",jsonResults);
int count = [[jsonResults valueForKey:#"count"] intValue];
NSArray *arrayData = [jsonResults copy];
NSMutableArray *arrayPDFName = [[NSMutableArray alloc]init];
for(int i = 0;i < [arrayData count];i++)
{
NSDictionary *dictOriginal = [[arrayData objectAtIndex:2]valueForKey:#"original"];
int countOriginal = [[dictOriginal valueForKey:#"count"] intValue];
NSLog(#"The countOriginal is - %d",countOriginal);
NSArray *arrayFiles = [[dictOriginal valueForKey:#"files"] copy];
NSLog(#"The arrayFiles are - %#",arrayFiles);
for(int j=0;j<[arrayFiles count];j++)
{
NSString *strCreatedTime = [NSString stringWithFormat:#"%#",[[arrayFiles objectAtIndex:j] valueForKey:#"created_time"]];
NSString *strLastModifiedTime = [NSString stringWithFormat:#"%#",[[arrayFiles objectAtIndex:j] valueForKey:#"last_modified_time"]];
NSString *strID = [NSString stringWithFormat:#"%#",[[arrayFiles objectAtIndex:j] valueForKey:#"id"]];
NSString *strName = [NSString stringWithFormat:#"%#",[[arrayFiles objectAtIndex:j] valueForKey:#"name"]];
NSLog(#"The created_time is - %#",strCreatedTime);
NSLog(#"The last_modified_time is - %#",strLastModifiedTime);
NSLog(#"The is is - %#",strID);
NSLog(#"The name is - %#",strName);
[arrayPDFName addObject:strName];
}
}
I have managed to extract the following array (which I am dumping to console) from some json. How can I get and print out the value for one of the elements, i.e. task?
Objective-C:
NSArray *array = [dict objectForKey:#"row"];
NSLog(#"array is: %#",array);
Console output:
array is: {
0 = 1;
1 = "send email";
2 = "with attachment";
ltask = "with attachment";
task = "send email";
userid = 1;
}
array looks like it is actually an NSDictionary, so reference the key to get the value for it.
NSLog(#"Task: %#", array[#"task"]);
the variable array doesn't seem to be NSArray . Does this work for you?
id array = [dict objectForKey:#"row"];
if([array isKindOfClass:[NSDictionary class]]){
NSLog(#"Value of task %#",array[#"task"]);
}
From the log, it looks like the output is an NSDictionary object, so to get the value of task key just do this
NSDictionary *myDict = dict[#"row"];
NSString *task = myDict[#"task"];
NSLog(#"task = %#", task);
if you want to confirm just check the class type using isKindOfClass: method
if([dict[#"row"] isKindOfClass:[NSDictionary class]]) {
NSDictionary *myDict = dict[#"row"];
NSString *task = myDict[#"task"];
NSLog(#"task = %#", task);
} else if([dict[#"row"] isKindOfClass:[NSArray class]]) {
NSArray *myArray = dict[#"row"];
NSDictionary *myDict = myArray[0];
NSString *task = myDict[#"task"];
NSLog(#"task = %#", task);
}
try
if ([[dictionary allKeys] containsObject:#"row"]) {
NSObject *objRow = dictionary[#"row"];
if(objRow){
if([objRow isKindOfClass:[NSArray class]]){
NSArray *arr = (NSArray *)objRow;
....
}
if([objRow isKindOfClass:[NSDictionary class]]){
NSDictionary *dic = (NSDictionary *)objRow;
....
}
}
}
It seems that since XCode 6.1, the iPhone 5S, iPhone 6 and iPhone 6+ simulators (all 64-bit) all return data from the following system method differently (keys are ordered differently) than their 32-bit simulator counterparts (e.g. iPhone 5 simulator)
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
This difference of key ordering caused a problem for me since we calculate the SHA1 of that JSON data (converted to NSString*) and use it for a validation test. Since the ordering changed, the SHA1 changed and the validation fails.
Simplified sample code (non-ARC) to get the SHA1 is below:
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:0
error:&error];
NSString * json = [[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] autorelease];
NSString * sha1 = [MyUtils computeSHA1:json];
+(NSString*) computeSHA1:(NSString*)input
{
const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:input.length];
NSNumber* dataLen = [NSNumber numberWithUnsignedInteger:data.length];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, dataLen.unsignedIntValue, digest);
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x", digest[i]];
return output;
}
Apparently, this key ordering difference doesn't happen on the actual devices (previous behavior was preserved).
I also tried with the NSJSONWritingPrettyPrinted option but the JSON ordering is still inconsistent between simulators.
So, the question is: Does anyone have a recommendation on how to normalize such JSON data so as to not be susceptible to key ordering changes? Alternately, is there any way to get the previous (32-bit simulator) behavior?
Key ordering in dictionaries is not guaranteed. If you need them sorted, put them into an array and sort them.
The code below (non-ARC) worked for me to better canonicalize JSON output. The code assumes the class methods below are all in a class called MyUtils.
Simply pass the the NSDictionary to serialize into "canonicalized JSON" to canonicalJSONRepresentationWithDictionary:
The returned NSString* then contains serialized JSON that has the keys ordered lexicographically/alphabetically in a non-human readable format.
+(NSString *) canonicalJSONRepresentationWithDictionary:(NSDictionary *)dict
{
NSMutableString* json = [NSMutableString string];
[json appendString:#"{"];
NSArray* keys = [[dict allKeys] sortedArrayUsingComparator:^NSComparisonResult(NSString* a, NSString* b) {
return [a compare:b];
}];
for (int i = 0; i < keys.count; i++) {
NSString* key = keys[i];
[json appendFormat:#"\"%#\":", key];
if ([dict[key] isKindOfClass:[NSString class]]) {
[json appendFormat:#"\"%#\"", [MyUtils canonicalJSONRepresentationWithString:dict[key]]];
} else if ([dict[key] isKindOfClass:[NSDictionary class]]) {
[json appendString:[MyUtils canonicalJSONRepresentationWithDictionary:dict[key]]];
} else if ([dict[key] isKindOfClass:[NSArray class]]) {
[json appendString:[MyUtils canonicalJSONRepresentationWithArray:dict[key]]];
} else {
return nil;
}
if (i < keys.count - 1) {
[json appendString:#","];
}
}
[json appendString:#"}"];
return json;
}
+(NSString *) canonicalJSONRepresentationWithArray:(NSArray *) array
{
NSMutableString* json = [NSMutableString string];
[json appendString:#"["];
for (int i = 0; i < array.count; i++) {
if ([array[i] isKindOfClass:[NSString class]]) {
[json appendFormat:#"\"%#\"", [MyUtils canonicalJSONRepresentationWithString:array[i]]];
} else if ([array[i] isKindOfClass:[NSDictionary class]]) {
[json appendString:[MyUtils canonicalJSONRepresentationWithDictionary:array[i]]];
} else if ([array[i] isKindOfClass:[NSArray class]]) {
[json appendString:[MyUtils canonicalJSONRepresentationWithArray:array[i]]];
} else {
return nil;
}
if (i < array.count - 1) {
[json appendString:#","];
}
}
[json appendString:#"]"];
return json;
}
+(NSString *) canonicalJSONRepresentationWithString:(NSString *) string;
{
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:string, #"a", nil];
NSError * error;
NSData * jsonData = nil;
NSString * json = nil;
jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:0
error:&error];
if (!jsonData) {
NSLog(#"Got an error serializing json: %#", error);
return nil;
} else {
json = [[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] autorelease];
}
NSRange colonQuote = [json rangeOfString:#":\""];
NSRange lastQuote = [json rangeOfString:#"\"" options:NSBackwardsSearch];
NSRange range = NSMakeRange(colonQuote.location + 2, lastQuote.location - colonQuote.location - 2);
NSString* rc = [json substringWithRange:range];
return rc;
}
I have a NSDictionary looks like this:
data = {
start = {
name = "abc";
age = "123";
id = AA838DDE;
};
};
how can I parser the dictionary to get individual name, age, and id? Thanks.
NSString *name = dictionary[#"data"][#"start"][#"name"];
I add an other answer because I hate the new Objective-C syntax (sorry #Raphael Olivieira)
NSString *name = [[[[dictionary objectForKey:#"data"] objectForKey:#"start"] objectAtIndex:0] objectForKey:#"name"];
NSLog(#"%#", name);
Longer than the previous answer but you know what you do and you don't code in C.
BTW, using the other syntax :
NSString *name = dictionary[#"data"][#"start"][0][#"name"];
NSLog(#"%#", name);
why don't you simply try:
int arrCount = [[[dictionaryObject valueForKey:#"data"] objectForKey:#"start"] count];
for(int i = 0 ; i < arrCount ; i++)
{
NSString *strName = [[[[dictionaryObject objectForKey:#"data"]
objectForKey:#"start"]
objectAtIndex:i]
objectForKey:#"name"];
NSString *strAge = [[[[dictionaryObject objectForKey:#"data"]
objectForKey:#"start"]
objectAtIndex:i]
objectForKey:#"age"];
NSString *strID = [[[[dictionaryObject objectForKey:#"data"]
objectForKey:#"start"]
objectAtIndex:i]
objectForKey:#"id"];
NSLog(#"%# - %# - %#", strName, strAge, strID);
}
I have a simple JSON array that is returned from a zip code passed to a third party service.
http://api.geonames.org/findNearbyPostalCodes?postalcode=94115&country=US&radius=5&username=frequentz
I get an unknown error when trying to deserialize the results and I'm not sure what is going wrong.
Here is my connectionDidFinishLoading method, which fires as anticiapated but always fails...and I get the error in the last else if. Ideas?
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"connectionDidFinishLoading...");
self.zipCodes = [NSMutableArray array];
NSError *error = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:receivedData options:NSJSONReadingAllowFragments error:&error];
if (jsonObject != nil && error == nil) {
NSLog(#"Successfully deserialized...");
if ([jsonObject isKindOfClass:[NSDictionary class]]) {
NSDictionary *deserializedDictionary = (NSDictionary *)jsonObject;
NSLog(#"Deserialized JSON Dictionary = %#", deserializedDictionary);
for (NSDictionary *item in jsonObject) {
NSString *city = [item objectForKey:#"adminName2"];
NSString *stateAbbreviation = [item objectForKey:#"adminCode1"];
NSString *postalCode = [item objectForKey:#"postalCode"];
NSString *distance = [item objectForKey:#"distance"];
NSString *country = [item objectForKey:#"country"];
NSString *stateName = [item objectForKey:#"stateName"];
ZipCodes *zipCode = [[ZipCodes alloc] initWithName:city stateAbbrev:stateAbbreviation postalCode:postalCode distanceFromGPSZip:distance country:country stateFullName:stateName];
[self.zipCodes addObject:zipCode];
}
}
else if ([jsonObject isKindOfClass:[NSArray class]]){
NSArray *deserializedArray = (NSArray *)jsonObject;
NSLog(#"Deserialized JSON Array = %#", deserializedArray);
}
else {
/* Some other object was returned. We don't know how to deal
with this situation as the deserializer returns only dictionaries or arrays */
}
}
else if (error != nil){
NSLog(#"An error happened while deserializing the JSON data.");
}
}
I think you're using the wrong service --it should be ...findNearbyPostalCodesJSON.... To use the JSON service as far as I can tell from their website. This is their example URL:
http://api.geonames.org/findNearbyPostalCodesJSON?postalcode=8775&country=CH&radius=10&username=demo