Search code examples
iosobjective-curlnsxmlparserweather-api

Yahoo weather API using NSXMLParser


This is the documentation provided by Yahoo: http://developer.yahoo.com/weather/

At the moment this is my code:

NSString *location =  @"Palermo";
NSString *temperatureUnit = @"c";
NSString *address = @"http://weather.yahooapis.com/forecastrss?w=";
NSString *request = [NSString stringWithFormat:@"%@%@&u=%@",address,location, temperatureUnit];
NSURL * URL = [NSURL URLWithString:request];
NSXMLParser * doc = [[NSXMLParser alloc] initWithContentsOfURL:URL];

I'd like to know how to get the temperature value using NSXMLParser


Solution

  • You create your parser, but you don't parse. Let's assume you created your parser like so:

    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL];
    

    You then need to set the delegate and initiate the parse:

    parser.delegate = self;
    [parser parse];
    

    You then have to write your NSXMLParserDelegate methods. (For more information on NSXMLParser, see the Event-Driven XML Programming Guide.) E.g., if you only need temperature, you could write a didStartElement method:

    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
    {
        if ([elementName isEqualToString:@"yweather:condition"])
        {
            // do whatever you want with `attributeDict`, perhaps saving it in some class property; I'm just going to log it
    
            NSLog(@"current condition = %@", attributeDict); 
        }           
    }
    

    Note, the city should be a WOEID. (See the API description.) So, instead of a location of:

    NSString *location =  @"Palermo";
    

    You should use (for Palermo in Italy):

    NSString *location =  @"719846";
    

    By the way, I agree with Caleb that you should either do this initWithContentsOfURL in a background queue, or you should otherwise retrieve the NSData using some asynchronous mechanism.

    For example, you could do:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSString *location = @"719846";
        NSString *temperatureUnit = @"c";
        NSString *address = @"http://weather.yahooapis.com/forecastrss?w=";
        NSString *request = [NSString stringWithFormat:@"%@%@&u=%@",address,location, temperatureUnit];
        NSURL *URL = [NSURL URLWithString:request];
    
        NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL];
        parser.delegate = self;
        [parser parse];
    });
    

    If you do this in the background queue, make sure to dispatch UI updates back to the main queue, e.g.:

    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
    {
        if ([elementName isEqualToString:@"yweather:condition"])
        {
            // UI updates should be dispatched back to the main queue, e.g.:
            dispatch_async(dispatch_get_main_queue(), ^{
                NSString *temp = attributeDict[@"temp"];
                self.tempLabel.text = temp;
            });
        }
    }