// // ForwardGeocode.h // #import #import #import #import #import @interface ForwardGeocode : NSObject { double _Latitude; double _Longitude; } - (BOOL) geoCodeZip :(NSString *) zip; - (double) Latitude; - (double) Longitude; - (void) setLatitude : (double) latitude; - (void) setLongitude: (double) longitude; @end // // ForwardGeocode.m // #import "ForwardGeocode.h" // Yahoo! PlaceFinder zip code query should look like this // http://where.yahooapis.com/geocode?appid=ReplaceWithYourAppID&zip=66045 #define PLACEFINDERURL @"http://where.yahooapis.com/geocode?appid=ReplaceWithYourAppID" @implementation ForwardGeocode - (double) Latitude { return _Latitude; } - (double) Longitude { return _Longitude; } - (void) setLatitude : (double) latitude { _Latitude = latitude; } - (void) setLongitude: (double) longitude { _Longitude = longitude; } void getOneResult(ForwardGeocode *geoCoder, xmlNodePtr curr, xmlDocPtr doc) { curr = curr->xmlChildrenNode; xmlChar *_long, *_lat; if (!curr) return; while (curr && (curr->type == XML_TEXT_NODE)) curr = curr->next; if (!curr) return; // skip to Latitude while (curr && xmlStrcmp(curr->name, (const xmlChar *)"latitude")) { curr = curr->next; } if (!curr) return; // Get Latitude if ((!xmlStrcmp(curr->name, (const xmlChar *)"latitude")) && (curr->type == XML_ELEMENT_NODE)) { _lat = xmlNodeListGetString(doc, curr->xmlChildrenNode, 1); curr = curr->next; while (curr && (curr->type == XML_TEXT_NODE)) curr = curr->next; if (!curr) { xmlFree(_lat); return; } } else return; // skip to Longitude (we know Latitude preceeds Longitude in the return set) while (curr && xmlStrcmp(curr->name, (const xmlChar *)"longitude")) { curr = curr->next; } // Get Longitude if ((!xmlStrcmp(curr->name, (const xmlChar *)"longitude")) && (curr->type == XML_ELEMENT_NODE)) { _long = xmlNodeListGetString(doc, curr->xmlChildrenNode, 1); curr = curr->next; while (curr && (curr->type == XML_TEXT_NODE)) curr = curr->next; if (!curr) { xmlFree(_lat); xmlFree(_long); return; } } else return; // Unusual coordinates for the US much less planet Earth double lat = -111111.0, llong = -111111.0; if (_lat) lat = strtod( (const char *)_lat, NULL ); if (_long) llong = strtod( (const char *)_long, NULL ); if ((lat != -111111.0) && (llong != -111111.0)) { [geoCoder setLatitude:lat]; [geoCoder setLongitude:llong]; } xmlFree(_lat); xmlFree(_long); } // ResultSet is the top level container for the result // Result contains elements associated with a single match result. void getResult(ForwardGeocode *geoCoder, xmlNodePtr curr, xmlDocPtr doc) { // null basis, we're done if (!curr) return; // This is the Result container, get the latitude and longitude by calling getOneResult if ((!xmlStrcmp(curr->name, (const xmlChar *)"Result")) && (curr->type == XML_ELEMENT_NODE)) { getOneResult(geoCoder, curr, doc); } // This is a text node we're not interested in if (curr->type == XML_TEXT_NODE) { getResult(geoCoder, curr->next, doc); } // Top level element. We're interested in "Result" and "ResultSet" // Don't recurse down into other types (Error, ErrorMessage, Locale, Quality, or Found) if (curr->type == XML_ELEMENT_NODE) { if ((!xmlStrcmp(curr->name, (const xmlChar *)"Result"))) { getResult(geoCoder, curr->next, doc); } else if (!xmlStrcmp(curr->name, (const xmlChar *)"ResultSet")) { getResult(geoCoder, curr->xmlChildrenNode, doc); } } return; } - (BOOL) geoCodeZip :(NSString *) zip { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; BOOL error = YES; NSError *err = nil; NSString *baseString = PLACEFINDERURL; NSString *zipURL = [baseString stringByAppendingFormat: @"&zip=%@", zip]; NSURL* url = [NSURL URLWithString:zipURL]; if (!url) return error; NSString *URLContents = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&err]; if (!URLContents || ([URLContents length] == 0)) { return error; } const char *XMLChars = [URLContents cStringUsingEncoding:NSUTF8StringEncoding]; xmlDocPtr doc = xmlParseMemory(XMLChars, strlen(XMLChars)); xmlNodePtr cur; if (doc == NULL) { return error; } cur = xmlDocGetRootElement(doc); if (cur) { _Latitude = -1.0; _Longitude = -1.0; getResult(self, cur, doc); if ((_Latitude != -1.0) || (_Longitude != -1.0)) { error = NO; } } xmlFreeDoc(doc); [pool release]; return error; } @end