National Weather Service Data Consumption with IPWorks

Requirements: IPWorks .Net Edition
Download Demo: Download

5 Day Forecast

The NWS (National Weather Service) maintains a massive database of weather data called NDFD (National Digital Forecast Database), which is publicly accessible through the NDFD SOAP Service.

In this article I will take a look at what this service has to offer, and create a "5 Day Forecast" demo using C#. In the demo I'll use the SOAP component from IPWorks .Net Edition to consume the NDFD SOAP service.

National Digital Forecast Database XML Web Service

The service provides access to the following meteorological data:

  • Maximum Temperature
  • Minimum Temperature
  • 3 hourly Temperature
  • Dew point Temperature
  • 12 hour Probability of Precipitation
  • Liquid Precipitation Amounts (Quantitative Precipitation Forecast)
  • Snowfall Amounts
  • Cloud Cover Amounts
  • Wind Direction
  • Wind Speed
  • Sensible Weather (Weather Type, Coverage, and Intensity)
  • Wave Heights

The service offers two methods:

  • NDFDgen
  • NDFDgenByDay

NDFDgen

The NDFDgen method returns a dataset for a time range. The resultant dataset can contain either all of the meteorological data listed above, or a subset specified by the request sent to the service.

NDFDgenByDay

The NDFDgenByDay method returns a dataset for a particular day count, i.e., a five day forecast. This is what I'll use in my demo. I'll use the SOAP component from IPWorks .Net Edition to consume the NWS service and the XML component to parse the resulting XML from the service response.

The NDFDgenByDay method takes 5 input parameters. The first two, latitude and longitude, I'll get from another service that outputs a latitude and longitude given a zip code as input (I won't talk about this here, but you can see it in the demo). For the startDate input I will use the current date. The numDays input will be hard coded to 5 in this demo, since the demo will be a "5 Day Forecast" demo. The final input, format, can be either "12 hourly" or "24 hourly". I want data specific to day and night, so I'll use the "12 hourly" format to get data for every 12 hours (day, 6am-6pm, and night, 6pm-6am).

Consume the SOAP Service

To consume the SOAP service, we will need to set the MethodURI, ActionURI, URL, Method, and any required parameters. While this will vary from request to request, here is a sample for retrieving a 5-day forecast, starting today, at the National Weather Service headquarters.

string baseUri = "http://graphical.weather.gov/xml/";
soap1.MethodURI = baseUri + "DWMLgen/wsdl/ndfdXML.wsdl";
soap1.ActionURI = baseUri + "DWMLgen/wsdl/ndfdXML.wsdl#NDFDgenByDay";
soap1.URL       = baseUri + "SOAP_server/ndfdXMLserver.php";
soap1.Method = "NDFDgenByDay";
soap1.AddParam("latitude", "38.9936");
soap1.AddParam("longitude", "-77.0224");
soap1.AddParam("startDate", DateTime.Now.ToString("yyyy-MM-dd"));
soap1.AddParam("numDays", "5");
soap1.AddParam("Unit", "e");
soap1.AddParam("format", "12 hourly");
soap1.SendRequest();

Parse the SOAP Response

The server response to the SOAP request can be gotten from the ReturnValue property after the SendRequest method returns. In this case, the ReturnValue will not be a simple string - instead it will be XML data containing forecast details. I'll use the XML component to parse this data to get out only what I want.

string xmldata = soap1.ReturnValue;
//pass the XML data to the XML component:
xml1.Reset();
xml1.InputData = xmldata;
xml1.Parse();

What day is it?

The XML response gives me three lists of "time-layouts" which establish a frame a reference for the rest of the meteorological data in the response. The first time layout shows all of the days. The second shows all of the nights, and the third shows days and nights. I'll use the first one (just the names of the days), but I could use any of them. This time-layout tells me what time periods the weather data is for. Below you can see this time-layout. It starts with today and tomorrow. Since this particular SOAP request was sent on a Friday, the day after tomorrow would be Sunday, and so on. Since I sent "5" as the numDaysparameter there are 5 days listed in the time-layouts.

<time-layout time-coordinate="local" summarization="12hourly">
  <layout-key>k-p24h-n5-1</layout-key>
    <start-valid-time period-name="today">
      2005-01-14T06:00:00-05:00
    </start-valid-time>
      <end-valid-time>2005-01-14T18:00:00-05:00</end-valid-time>
    <start-valid-time period-name="tomorrow">
      2005-01-15T06:00:00-05:00
     </start-valid-time>
      <end-valid-time>2005-01-15T18:00:00-05:00</end-valid-time>
    <start-valid-time period-name="Sunday">
      2005-01-16T06:00:00-05:00
    </start-valid-time>
      <end-valid-time>2005-01-16T18:00:00-05:00</end-valid-time>
    <start-valid-time period-name="Monday">
      2005-01-17T06:00:00-05:00
    </start-valid-time>
      <end-valid-time>2005-01-17T18:00:00-05:00</end-valid-time>
    <start-valid-time period-name="Tuesday">
      2005-01-18T06:00:00-05:00
    </start-valid-time>
      <end-valid-time>2005-01-18T18:00:00-05:00</end-valid-time>
</time-layout>

I'll use this time-layout to gather the day labels for my GUI. To strip out these names, I'll use the XML component to parse out all of the "period-name" attributes from the start-valid-time child of the time-layout element. I'll add this period-name to an ArrayList, like so:

xml1.XPath = "/dwml/data/time-layout[1]"; //this time-layout is the 2nd data child
int numtimeelements = xml1.XChildren.Count;
for (int i = 1; i<=numtimeelements; i++) 
{
  xml1.XPath = "/dwml/data/time-layout[1]/[" + i.ToString() + "]";
  if (xml1.XElement == "start-valid-time") 
  {
    daytitles.Add(xml1.Attr("period-name"));
  }
}

Meteorological Data

The guts of all of this weather data is found in the /dwml/data/parameters element. There are several XML child elements here with different pieces of data for each time period:

  • <temperature> - the min and max temperatures.
  • <probability-of-precipitation> - the chance of precipitation percentage.
  • <weather> - A brief phrase describing the weather conditions in English
  • <conditions-icon> - a URL to an image describing the weather conditions.

To deal with all of this data, I'll visit each child of the /dwml/data/parameters/ element and parse it appropriately:

xml1.XPath = "/dwml/data/parameters"; 
int numparameterelements = xml1.XChildren.Count;
for (int i=1; i<=numparameterelements; i++) 
{
  xml1.XPath = "/dwml/data/parameters/[" + i.ToString() + "]";
  switch (xml1.XElement) 
  {
    case("temperature"): 
      GetTemperatures();
      break;
    case("probability-of-precipitation"): 
      GetPrecipitationChance(xml1.XPath); 
      break;
    case("weather"): 
      GetWeather(xml1.XPath);
      break;
    case("conditions-icon"): 
      GetIcons(xml1.XPath); 
      break;
  }
}

Each of the above functions (GetTemperatures, GetPrecipitationChance, GetWeather, and GetIcons) works similarly to the code above, in that they strip out the relevant data. These functions simply populate an ArrayList with their information. After all of the ArrayLists are populated, I display the data that I've gathered, as shown in the image above.


We appreciate your feedback.  If you have any questions, comments, or suggestions about this article please contact our support team at kb@nsoftware.com.