Ziff Davis EnterpriseDevLife
Advertisement
Advertisement

Monday, September 28, 2009 9:56 PM/EST

Building an XML file with Google’s Weather and LINQ to XML

I had a need to create an xml file that contains tomorrow's weather forecasts for selection of addresses in a database. I spent way too much time working this out, so thought I would share for the next dev down the road.

The first step, which took quite a while, was to find an RSS feed or web service that supplies the forecasts.

Much time was wasted chasing down dead ends, for example a no-longer-existing API from Google for which you will find lots of references and how-to's if you search the web. In the end, I decided to go with http://www.google.com/ig/api?weather which returns some simple forecast info given a location (us zip code, city/state, city/country and other combinations.

Now I could use my address data to dynamically build URIs which I can then call using XElement.Load (no bothering with web services or WebRequest/WebResponse).

After calling each URI, I use LINQ to XML to get the forecast from the results and then build a struct which I add to a list.

When I have iterated through all of the addresses, I use LINQ to XML one last time to create the final XML and then persist that to a file.

This file is something I want to leverage in a sample in the new version of my book Programming Entity Framework, so I am using that data.

I have a Lodgings entity that is realted to Contact which is related to Addresses. So for each lodging, I extract the critical address information.

   1: var lodgingCityCountry = 
                  from l in context.Lodgings

   2:             select new

   3:             {

   4:               l.LodgingID,

   5:               l.Contact.Addresses.FirstOrDefault().City,

   6:               l.Contact.Addresses.FirstOrDefault().StateProvince,

   7:               l.Contact.Addresses.FirstOrDefault().CountryRegion

   8:            };


Next I iterated through each result and build a uri. I have to be careful not to pass in nulls and to build appropriate uris.

   1:  foreach (var l in lodgingCityCountry)

   2:  {

   3:      string uri;

   4:      if ((l.StateProvince == null && l.City == null 
&& l.CountryRegion == null) == false)

   5:      {

   6:          string region;

   7:          if(l.CountryRegion !=null)

   8:          {region= "," + l.CountryRegion.Trim();

   9:          }

  10:          else

  11:          {   region="";

  12:          }

  13:          if (l.StateProvince != null)

  14:          {

  15:              uri = "http://www.google.com/ig/api?weather=" +
                          l.City.Trim() + "," +
                          l.StateProvince.Trim() + region;

  16:          }

  17:          else

  18:          {

  19:              uri = "http://www.google.com/ig/api?weather=" +
                         l.City.Trim() +region;

  20:          }


Next, load the results into an XElement.

   1:  System.Xml.Linq.XElement googleRSS = System.Xml.Linq.XElement.Load(uri);

Here's what the XML looks like. It contains the current conditions and forecsat info for current day and the next three days.

<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="Tucson, AZ" /> 
      <postal_code data="Tucson,Arizona,United States" /> 
      <latitude_e6 data="" /> 
      <longitude_e6 data="" /> 
      <forecast_date data="2009-09-28" /> 
      <current_date_time data="2009-09-29 00:11:57 +0000" /> 
      <unit_system data="US" /> 
    </forecast_information>
    <current_conditions>
      <condition data="Clear" /> 
      <temp_f data="102" /> 
      <temp_c data="39" /> 
      <humidity data="Humidity: 12%" /> 
      <icon data="/ig/images/weather/sunny.gif" /> 
      <wind_condition data="Wind: SW at 4 mph" /> 
    </current_conditions>
    <forecast_conditions>
      <day_of_week data="Mon" /> 
      <low data="68" /> 
      <high data="103" /> 
      <icon data="/ig/images/weather/sunny.gif" /> 
      <condition data="Clear" /> 
    </forecast_conditions>
..tues, wed, thurs forecasts as well </weather> </xml_api_reply>

I only want some of the forecast info for tomorrow so I use LINQ to XML to grab them.

   1:  var items = from item in googleRSS.Elements("weather")

   2:                  .Elements("forecast_conditions")

   3:              select item;


Now that's all of the forecast items. I only want the first one, but I have to be careful in case there is no data so the next steps are wrapped in a try/catch.

I grab the second one (the first is today's forecast)

   1:  if (items.Count > 0)

   2:  {

   3:      var tomorrow = items.ToList()[1];

Then I create a new LodgingForecast struct (I'll show the definition of this at the end) from the ID of the lodging and a concatenated string of forecast information.

   4: forecasts.Add(new LodgingForecast


   5: {

   6:   lodgingID = l.LodgingID,

   7:   forecast = (String)tomorrow.Element("condition").Attribute("data").Value

   8:   + ", Low: " + (String)tomorrow.Element("low").Attribute("data").Value

   9:   + ", High: " + (String)tomorrow.Element("high").Attribute("data").Value

  10:   });

  11:  }



After closing the remaining braces,  I will have finished iterating through the addresses and building my list of forecasts for each Lodging.

I use LINQ to XML one last time to create a nice XML file based on the list.

   1:  XElement forecastsXML = new XElement("Forecasts", 

   2:      from f in forecasts 

   3:      select new XElement("Lodging", 

   4:                           new XAttribute("ID", f.lodgingID), 

   5:                           new XAttribute("forecast", f.forecast)));


Finally I create an XDocument from this XElement and save it to a file.

   1:  Document doc = new XDocument(

   2:                     new XDeclaration("1.0", "utf-8", "yes"),

   3:                     new XComment("LodgingForecasts"),

   4:                     forecastsXML);

   5:  doc.Save(@"LodgingForecasts.xml");



Now the app can cache this data once a day and access it locally without having to requery the web.

Here's the struct referenced earlier.

   1:    struct LodgingForecast

   2:    {

   3:      public int lodgingID;

   4:      public String forecast;

   5:    }

TrackBack

TrackBack

http://blogs.devsource.com/cgi-bin/mte/mt-tb.cgi/17974

Post a Comment

 
 

Advertisement

Syndication

Subscribe: