Tutorial - National Weather Service Data Consumption with IP*Works!
By Lance Robinson - Technical Evangelist, /n software.
Requirements:
IP*Works! .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 publically 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 IP*Works! .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
- Dewpoint 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
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 (ie, a five day forecast). This is what I'll use in my demo.
I'll use the SOAP component from IP*Works! .Net Edition to consume the NWS service and the XMLp 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
Using the /n software Web Service Proxy Generator helper app, I can automatically
generate code that will consume this service. I simply give it a link to the WSDL document for the service
(http://weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl),
and it will generate code for the SOAP component in the language of my choice. I'll choose C#, and the code is generated for me.
When I plug the code into my own application and modify it to use my own parameter inputs, it will look like so:
string baseUri = "http://www.nws.noaa.gov/forecasts/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", latitude);
soap1.AddParam("longitude", longitude);
soap1.AddParam("startDate", DateTime.Now.ToString("yyyy-MM-dd"));
soap1.AddParam("numDays", "5");
soap1.AddParam("format", "12 hourly");
soap1.SendRequest();
The Proxy Generator automatically found the correct MethodURI, ActionURI, URL, Method, and Parameter names from the WSDL. I modified
the values of the data passed to AddParam to the values I want: latitude and longitude are variables that were set
already. Their default is the location of the National Weather Service headquarters: Lat,Lon : (38.9936,-77.0224).
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
XMLp component to parse this data to get out only what I want.
string xmldata = soap1.ReturnValue;
//pass the XML data to the XMLp component:
xmlp1.Reset();
xmlp1.Input(xmldata);
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 I sent this particular soap request on a Friday, after tomorrow night comes Sunday and so on. Since
I sent "5" as the numDays parameter 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 XMLp 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:
xmlp1.XPath = "/dwml/data/time-layout[1]"; //this time-layout is the 2nd data child
int numtimeelements = xmlp1.XChildren;
for (int i = 1; i<=numtimeelements; i++)
{
xmlp1.XPath = "/dwml/data/time-layout[1]/[" + i.ToString() + "]";
if (xmlp1.XElement == "start-valid-time")
{
daytitles.Add(xmlp1.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:
xmlp1.XPath = "/dwml/data/parameters";
int numparameterelements = xmlp1.XChildren;
for (int i=1; i<=numparameterelements; i++)
{
xmlp1.XPath = "/dwml/data/parameters/[" + i.ToString() + "]";
switch (xmlp1.XElement)
{
case("temperature"): GetTemperatures(); break;
case("probability-of-precipitation"):
GetPrecipitationChance(xmlp1.XPath); break;
case("weather"): GetWeather(xmlp1.XPath); break;
case("conditions-icon"): GetIcons(xmlp1.XPath); break;
}
}
Each of these functions above (GetTemperatures, GetPrecipitationChance, GetWeather, and GetIcons) work similarly to the
code above that strips out the day titles. 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.
If you'd like to see the full demo, you can download it here.
We appreciate your feedback. If you have any questions, comments, or
suggestions about this article please contact our support team at
kb@nsoftware.com.