Getting some weather data in your iOS application

Introduction

If you’ve ever wanted to load up some weather data and display it in your iOS application, you’ve probably come across several different ways of doing it. Most examples I’ve seen use the built-in NSXMLParser class, which is a SAX parser… meaning it’s event driven and returns bits of the resulting XML data as they are loaded. That’s probably cool for large XML files, but generally speaking weather XML documents are usually very small. And nested. Nesting is the bane of NSXMLParser (in my humble opinion). You need to keep track of where you are in the document as the lines of XML stream through via delegates. It’s not pretty. It’s not impossible, but wouldn’t you rather use a DOM model parser… allowing you to use XPath to pull out the bits you need? Yes, me too.

KissXML

I found a handy wrapper for the libxml2 library (which is written in C). With it you load the entire XML file before┬átraversing, you can read and generate XML, it has the same API as NSXML, behaves like NSXML and also behaves like a true Objective-C class. You can XPath the knickers off the resulting XML that resides in memory too. You can find the project page here and download the source, git it, whatever. Follow the instructions to bolt it into your application. Just remember to add the files to your project & add the compiler directives (2). Then #include “DDXML.h” where you’d like to use it. Getting started wiki page.

Google Weather

Let’s load up some weather data and parse it. If you’d like a sample bit of code showing you how to load up some weather data, I am including that below for reference. The DDXMLDocument object doesn’t have an initWithContentsOfURL but it does allow for initWithData. Perfect, we’ll just create the NSData ourselves.

Remember this is just an example… you can XPath the knickers to the ankles.

Example resulting XML from this URL (http://www.google.com/ig/api?weather=01701):

<xml_api_reply version="1">
<weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0">
<forecast_information>
  <city data="Framingham, MA"/>
  <postal_code data="01701"/>
  <latitude_e6 data=""/>
  <longitude_e6 data=""/>
<forecast_date data="2011-06-09"/>
<current_date_time data="2011-06-09 14:37:37 +0000"/>
<unit_system data="US"/>
</forecast_information>
    <current_conditions>
      <condition data="Sunny"/>
      <temp_f data="75"/>
      <temp_c data="24"/>
      <humidity data="Humidity: 79%"/>
      <icon data="/ig/images/weather/sunny.gif"/>
      <wind_condition data="Wind: W at 7 mph"/>
  </current_conditions>
<forecast_conditions>
  <day_of_week data="Thu"/>
  <low data="67"/>
  <high data="98"/>
  <icon data="/ig/images/weather/chance_of_storm.gif"/>
  <condition data="Scattered Thunderstorms"/>
</forecast_conditions>
<forecast_conditions>
  <day_of_week data="Fri"/>
  <low data="56"/>
  <high data="78"/>
  <icon data="/ig/images/weather/partly_cloudy.gif"/>
  <condition data="Partly Cloudy"/>
</forecast_conditions>
<forecast_conditions>
  <day_of_week data="Sat"/>
  <low data="56"/>
  <high data="69"/>
  <icon data="/ig/images/weather/rain.gif"/>
  <condition data="Showers"/>
</forecast_conditions>
<forecast_conditions>
  <day_of_week data="Sun"/>
  <low data="59"/>
  <high data="71"/>
  <icon data="/ig/images/weather/rain.gif"/>
  <condition data="Showers"/>
</forecast_conditions>
</weather>
</xml_api_reply>

And now for some code to show KissXML in action:

NSString *tmp = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://www.google.com/ig/api?weather=01701"] encoding:NSUTF8StringEncoding error:nil];
NSData *xmlData = [tmp dataUsingEncoding:NSUTF8StringEncoding];
DDXMLDocument *xmlDoc = [[[DDXMLDocument alloc] initWithData:xmlData options:0 error:nil] autorelease];
NSArray *resultNodes = nil;
resultNodes = [xmlDoc nodesForXPath:@"//forecast_conditions/day_of_week" error:nil];
for(DDXMLElement* resultElement in resultNodes){
    NSString *temp = [[resultElement attributeForName:@"data"] stringValue];
    NSLog(@"%@", temp);
}

NSArray *lowsData = [xmlDoc nodesForXPath:@"//forecast_conditions/low" error:nil];
for(DDXMLElement *res in lowsData){
    NSString *tt = [[res attributeForName:@"data"] stringValue];
    NSLog(@"low: %@",tt);
}

Not too shabby. No event delegates to muss with. No self-managed Booleans or counters. Traverse like a mouse in a maze if you’d like. Given the size of the returning XML, this approach is also wicked fast. So you if you’re coming from the AS3 Flash world, this is more what you’re used to. And for the case of nested documents, it’s much easier to use and to understand.

Related Posts Plugin for WordPress, Blogger...

One thought on “Getting some weather data in your iOS application

Leave a Reply

Your email address will not be published. Required fields are marked *


2 × nine =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>