outoftime-noaa 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,141 @@
1
+ module NOAA
2
+ #
3
+ # Representation of the current conditions for a given observation point.
4
+ #
5
+ class CurrentConditions
6
+
7
+ class <<self
8
+ private :new
9
+
10
+ def from_xml(doc) #:nodoc:
11
+ new(doc)
12
+ end
13
+ end
14
+
15
+ def initialize(doc) #:notnew:
16
+ @doc = doc
17
+ end
18
+
19
+ #
20
+ # Time object containing the time at which these conditions were observed at the NOAA station
21
+ #
22
+ def observed_at
23
+ @observed_at ||= Time.parse(text_from_node('observation_time_rfc822'))
24
+ end
25
+
26
+ #
27
+ # Text description of the current weather conditions, e.g. "Fair"
28
+ #
29
+ def weather_description
30
+ @weather_description ||= text_from_node('weather')
31
+ end
32
+
33
+ #
34
+ # The current temperature in the requested units.
35
+ #
36
+ # conditions.temperature #=> temperature in fahrenheit
37
+ # conditions.temperature(:c) #=> temperature in celsius
38
+ # conditions.temperature(:kelvin) #=> anything else raises an exception
39
+ #
40
+ def temperature(unit = :f)
41
+ text_from_node_with_unit('temp', unit, :f, :c).to_i
42
+ end
43
+
44
+ #
45
+ # The current relative humidity percentage (0-100)
46
+ #
47
+ def relative_humidity
48
+ text_from_node('relative_humidity').to_i
49
+ end
50
+
51
+ #
52
+ # The current cardinal or ordinal direction that the wind is coming from (e.g., "Northwest")
53
+ #
54
+ def wind_direction
55
+ text_from_node('wind_dir')
56
+ end
57
+
58
+ #
59
+ # The current direction that the wind is coming from degrees (e.g. 330)
60
+ #
61
+ def wind_degrees
62
+ text_from_node('wind_degrees').to_i
63
+ end
64
+
65
+ #
66
+ # The current wind speed in miles per hour as a float (e.g., 3.45)
67
+ #
68
+ def wind_speed
69
+ text_from_node('wind_mph').to_f
70
+ end
71
+
72
+ #
73
+ # The current wind gust in miles per hour as a float, or nil if none
74
+ #
75
+ def wind_gust
76
+ text_from_node('wind_gust_mph').to_f
77
+ end
78
+
79
+ #
80
+ # The current barometric pressure
81
+ #
82
+ # conditions.pressure #=> pressure in inches
83
+ # conditions.pressure(:mb) #=> pressure in millibars
84
+ # conditions.pressure(:psi) #=> anything else raises an exception
85
+ #
86
+ def pressure(unit = :in)
87
+ text_from_node_with_unit('pressure', unit, :in, :mb).to_f
88
+ end
89
+
90
+ #
91
+ # The current dew point.
92
+ #
93
+ # conditions.dew_point #=> dew point in fahrenheit
94
+ # conditions.dew_point(:c) #=> dew point in celsius
95
+ # conditions.dew_point(:kelvin) #=> anything else raises an exception
96
+ #
97
+ def dew_point(unit = :f)
98
+ text_from_node_with_unit('dewpoint', unit, :f, :c).to_i
99
+ end
100
+
101
+ #
102
+ # The current heat index
103
+ #
104
+ # conditions.heat_index #=> heat index in fahrenheit
105
+ # conditions.heat_index(:c) #=> heat index in celsius
106
+ # conditions.heat_index(:kelvin) #=> anything else raises an exception
107
+ #
108
+ def heat_index(unit = :f)
109
+ text_from_node_with_unit('heat_index', unit, :f, :c).to_i
110
+ end
111
+
112
+ #
113
+ # The current wind chill
114
+ #
115
+ # conditions.wind_chill #=> wind chill in fahrenheit
116
+ # conditions.wind_chill(:c) #=> wind chill in celsius
117
+ # conditions.wind_chill(:kelvin) #=> anything else raises an exception
118
+ #
119
+ def wind_chill(unit = :f)
120
+ text_from_node_with_unit('windchill', unit, :f, :c).to_i
121
+ end
122
+
123
+ #
124
+ # The current visibility in miles
125
+ #
126
+ def visibility
127
+ text_from_node('visibility_mi').to_f
128
+ end
129
+
130
+ private
131
+
132
+ def text_from_node(element_name)
133
+ @doc.find("/current_observation/#{element_name}[1]/child::text()").first.to_s
134
+ end
135
+
136
+ def text_from_node_with_unit(element_name, unit, *allowed_units)
137
+ raise ArgumentError, "Unknown unit #{unit.inspect} - allowed units are #{allowed_units.inspect}" unless allowed_units.include?(unit)
138
+ text_from_node("#{element_name}_#{unit}")
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,94 @@
1
+ module NOAA
2
+ #
3
+ # A Forecast object represents a multi-day forecast for a particular place. The forecast for a given day can
4
+ # be accessed using the [] method; e.g. (assuming +forecast+ is a forecast for 12/20/2008 - 12/24/2008):
5
+ #
6
+ # forecast[1] #=> ForecastDay for 12/21/2008
7
+ # forecast.length #=> 4
8
+ #
9
+ class Forecast
10
+
11
+ class <<self
12
+ private :new
13
+
14
+ def from_xml(doc) #:nodoc:
15
+ new(doc)
16
+ end
17
+ end
18
+
19
+ def initialize(doc) #:noinit:
20
+ @doc = doc
21
+ end
22
+
23
+ #
24
+ # The number of days provided by the forecast
25
+ #
26
+ def length
27
+ @length ||= @doc.find(%q{/dwml/data/time-layout[@summarization='24hourly'][1]/start-valid-time}).length
28
+ end
29
+
30
+ #
31
+ # Get the ForecastDay for day i
32
+ #
33
+ # forecast[1] #=> returns the ForecastDay for the second day
34
+ #
35
+ def [](i)
36
+ forecast_days[i]
37
+ end
38
+
39
+ private
40
+
41
+ def forecast_days
42
+ @forecast_days ||= begin
43
+ days = []
44
+ length.times do |i|
45
+ days << day = NOAA::ForecastDay.new
46
+ day.starts_at = starts[i]
47
+ day.ends_at = ends[i]
48
+ day.high = maxima[i]
49
+ day.low = minima[i]
50
+ day.weather_summary = weather_summaries[i]
51
+ day.daytime_precipitation_probability = precipitation_probabilities[i*2]
52
+ day.evening_precipitation_probability = precipitation_probabilities[i*2+1]
53
+ end
54
+ days
55
+ end
56
+ end
57
+
58
+ def starts
59
+ @starts ||= @doc.find(%q{/dwml/data/time-layout[@summarization='24hourly'][1]/start-valid-time/text()}).map do |node|
60
+ Time.parse(node.to_s)
61
+ end
62
+ end
63
+
64
+ def ends
65
+ @ends ||= @doc.find(%q{/dwml/data/time-layout[@summarization='24hourly'][1]/end-valid-time/text()}).map do |node|
66
+ Time.parse(node.to_s)
67
+ end
68
+ end
69
+
70
+ def maxima
71
+ @maxima ||= @doc.find(%q{/dwml/data/parameters[1]/temperature[@type='maximum'][@units='Fahrenheit'][1]/value/text()}).map do |node|
72
+ node.to_s.to_i
73
+ end
74
+ end
75
+
76
+ def minima
77
+ @minima ||= @doc.find(%q{/dwml/data/parameters[1]/temperature[@type='minimum'][@units='Fahrenheit'][1]/value/text()}).map do |node|
78
+ node.to_s.to_i
79
+ end
80
+ end
81
+
82
+ def weather_summaries
83
+ @weather_summaries ||= @doc.find(%q{/dwml/data/parameters[1]/weather[1]/weather-conditions}).map do |node|
84
+ node['weather-summary'].to_s
85
+ end
86
+ end
87
+
88
+ def precipitation_probabilities
89
+ @precipitation_probabilities ||= @doc.find(%q{/dwml/data/parameters[1]/probability-of-precipitation[1]/value/text()}).map do |node|
90
+ node.to_s.to_i
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,30 @@
1
+ module NOAA
2
+ #
3
+ # A ForecastDay contains forecast data for a single day. Each day should start at 6am and
4
+ # end at 6am the following day (assuming that is invariant on the part of the NOAA's data
5
+ # feed). ForecastDay objects are accessed using NOAA::Forecast#[]
6
+ class ForecastDay
7
+ # Time when this forecast's valid time span begins
8
+ attr_reader :starts_at
9
+
10
+ # Time when this forecast's valid time span ends
11
+ attr_reader :ends_at
12
+
13
+ # High temperature for the day in Fahrenheit
14
+ attr_reader :high
15
+
16
+ # Low temperature for the day in Fahrenheit
17
+ attr_reader :low
18
+
19
+ # String summary of weather (e.g., 'Fair')
20
+ attr_reader :weather_summary
21
+
22
+ # Percentage probability of precipitation during the day, between 6am and 6pm, as an integer (0-100)
23
+ attr_reader :daytime_precipitation_probability
24
+
25
+ # Percentage probability of precipitation during the evening/night, between 6pm and 6am, as an integer (0-100)
26
+ attr_reader :evening_precipitation_probability
27
+
28
+ attr_writer :starts_at, :ends_at, :high, :low, :weather_summary, :daytime_precipitation_probability, :evening_precipitation_probability #:nodoc:
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ module NOAA
2
+ class HttpService #:nodoc:
3
+ def initialize(http = Net::HTTP)
4
+ @HTTP = http
5
+ end
6
+
7
+ def get_current_conditions(station_id)
8
+ LibXML::XML::Document.string(@HTTP.get(URI.parse("http://www.weather.gov/xml/current_obs/#{station_id}.xml")))
9
+ end
10
+
11
+ def get_forecast(num_days, lat, lng)
12
+ LibXML::XML::Document.string(@HTTP.get(URI.parse("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?lat=#{lat}&lon=#{lng}&format=24+hourly&numDays=#{num_days}")))
13
+ end
14
+
15
+ def get_station_list
16
+ LibXML::XML::Document.string(@HTTP.get(URI.parse("http://www.weather.gov/xml/current_obs/index.xml")))
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,111 @@
1
+ module NOAA
2
+ #
3
+ # Data about an NOAA observation station. When accessing current conditions, the NOAA XML API
4
+ # takes a station ID as input; thus, to find the current conditions for an arbitrary location, one
5
+ # must first determine the closest weather station to that location. The NOAA.current_conditions
6
+ # method performs this task implicitly; however, for applications that need to find conditions
7
+ # for the same location(s) repeatedly, it is far more efficient to find the closest weather station
8
+ # once, store that information, and then query directly against the weather station when updated
9
+ # conditions are needed.
10
+ #
11
+ # Station data is stored in a YAML file that is created using the <tt>noaa-update-stations</tt> executable.
12
+ # Be sure to run this command at least once when you first install the NOAA library, and any time
13
+ # thereafter that you would like to get the latest list of stations. I don't imagine the list
14
+ # changes very often but I don't really have any idea.
15
+ #
16
+ class Station
17
+ class <<self
18
+ attr_writer :stations_file #:nodoc:
19
+
20
+ #
21
+ # Retrieve information about a station given a station ID
22
+ #
23
+ # NOAA::Station.find('KNYC') #=> NOAA::Station object for the Central Park station
24
+ def find(id)
25
+ stations.find { |station| station.id == id }
26
+ end
27
+
28
+ #
29
+ # Find the station closest to a given location. Can accept arguments in any of the following
30
+ # three forms (all are equivalent):
31
+ #
32
+ # NOAA::Station.closest_to(37.989, -77.507)
33
+ # NOAA::Station.closest_to([37.989, -77.507])
34
+ # NOAA::Station.closest_to(GeoKit::LatLng.new(37.989, -77.507))
35
+ def closest_to(*args)
36
+ if args.length == 1
37
+ if args.first.respond_to?(:distance_to)
38
+ closest_to_coordinates(args.first)
39
+ elsif %w(first last).all? { |m| args.first.respond_to?(m) }
40
+ closest_to_lat_lng(args.first)
41
+ else
42
+ raise ArgumentError, "expected two-element Array or GeoKit::LatLng"
43
+ end
44
+ elsif args.length == 2
45
+ closest_to_lat_lng(args)
46
+ else
47
+ raise ArgumentError, "closest_to() will accept one Array argument, one GeoKit::LatLng argument, or two FixNum arguments"
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def closest_to_lat_lng(pair)
54
+ closest_to_coordinates(GeoKit::LatLng.new(pair.first, pair.last))
55
+ end
56
+
57
+ def closest_to_coordinates(coordinates)
58
+ stations.map do |station|
59
+ [coordinates.distance_to(station.coordinates), station]
60
+ end.min do |p1, p2|
61
+ p1.first <=> p2.first # compare distance
62
+ end[1]
63
+ end
64
+
65
+ def stations
66
+ File.open(stations_file) do |file|
67
+ yaml = YAML.load(file) || raise("Can't parse #{file.path} - be sure to run noaa-update-stations")
68
+ yaml.map { |station_hash| new(station_hash) }
69
+ end
70
+ end
71
+
72
+ def stations_file
73
+ @stations_file ||= File.join(File.dirname(__FILE__), '..', '..', 'data', 'stations.yml')
74
+ end
75
+ end
76
+
77
+ # GeoKit::LatLng containing the station's coordinates
78
+ attr_reader :coordinates
79
+
80
+ # Station ID (e.g., "KNYC")
81
+ attr_reader :id
82
+
83
+ # Station name (e.g., "New York City, Central Park")
84
+ attr_reader :name
85
+
86
+ # Two-digit abbreviation for state in which station resides (e.g., "NY")
87
+ attr_reader :state
88
+
89
+ attr_reader :xml_url #:nodoc:
90
+
91
+ def initialize(properties)
92
+ @id, @name, @state, @xml_url = %w(id name state xml_url).map do |p|
93
+ properties[p]
94
+ end
95
+ @coordinates = GeoKit::LatLng.new(properties['latitude'], properties['longitude'])
96
+ end
97
+
98
+ # Latitude of station
99
+ def latitude
100
+ @coordinates.lat
101
+ end
102
+ alias_method :lat, :latitude
103
+
104
+ # Longitude of station
105
+ def longitude
106
+ @coordinates.lng
107
+ end
108
+ alias_method :lng, :longitude
109
+ alias_method :lon, :longitude
110
+ end
111
+ end
@@ -0,0 +1,26 @@
1
+ module NOAA
2
+ class StationWriter
3
+ def initialize(doc)
4
+ @doc = doc
5
+ end
6
+
7
+ def write(io)
8
+ YAML.dump(@doc.find('/wx_station_index/station').map { |node| node_to_hash(node) }, io)
9
+ end
10
+
11
+ private
12
+
13
+ def node_to_hash(node)
14
+ { 'latitude' => node_value(node, 'latitude').to_f,
15
+ 'longitude' => node_value(node, 'longitude').to_f,
16
+ 'id' => node_value(node, 'station_id'),
17
+ 'name' => node_value(node, 'station_name'),
18
+ 'state' => node_value(node, 'state'),
19
+ 'xml_url' => node_value(node, 'xml_url') }
20
+ end
21
+
22
+ def node_value(node, element)
23
+ node.find("./#{element}/text()").first.to_s
24
+ end
25
+ end
26
+ end
data/lib/noaa.rb ADDED
@@ -0,0 +1,61 @@
1
+ require 'rubygems'
2
+ gem 'libxml-ruby', '>= 0.9.7'
3
+ gem 'andre-geokit', '>= 1.2.0'
4
+
5
+ require 'time'
6
+ require 'libxml'
7
+ require 'geokit'
8
+
9
+ %w(current_conditions forecast forecast_day http_service station station_writer).each { |file| require File.join(File.dirname(__FILE__), 'noaa', file) }
10
+
11
+ #
12
+ # The NOAA singleton provides methods to conveniently access information from the NOAA weather feed.
13
+ # For the most part, NOAA.current_conditions and NOAA.forecast will be the only entry point into the
14
+ # NOAA API you will need; one exception is discussed below.
15
+ #
16
+ module NOAA
17
+ VERSION = '0.1.0'
18
+
19
+ class <<self
20
+ #
21
+ # Retrieve the current weather conditions for a given latitude and longitude. Returns an
22
+ # instance of NOAA::CurrentConditions.
23
+ #
24
+ # NOAA.current_conditions(37.989, -77.507) #=> NOAA::CurrentConditions encapsulating current conditions at this point
25
+ #
26
+ # <b>Note:</b> This method parses the stored list of all weather stations in the US and then finds the closest one to
27
+ # the given coordinates, as the NOAA XML API only takes a weather station ID as input. Clearly, this is an expensive
28
+ # operation; if your application needs to repeatedly request conditions for the same point, you will be much better off
29
+ # determining the current station once using NOAA::Station.closest_to, storing the station ID, and then passing it into
30
+ # NOAA.current_conditions_at_station when you need to get the latest conditions.
31
+ #
32
+ def current_conditions(lat, lng)
33
+ current_conditions_at_station(Station.closest_to(lat, lng))
34
+ end
35
+
36
+ #
37
+ # Retrieve the current weather conditions for a given weather station ID. Returns an
38
+ # instance of NOAA::CurrentConditions.
39
+ #
40
+ # NOAA.current_conditions_at_station('KNYC') #=> NOAA::CurrentConditions encapsulating current conditions in Central Park
41
+ #
42
+ # See discussion above regarding why this method is often preferable to simply calling #current_conditions.
43
+ #
44
+ def current_conditions_at_station(station_id)
45
+ CurrentConditions.from_xml(HttpService.new.get_current_conditions(station_id))
46
+ end
47
+
48
+ #
49
+ # Retrieve daily forecast information for a given latitude and longitude. Returns
50
+ # an instance of NOAA::Forecast.
51
+ #
52
+ # NOAA.forecast(4, 37.989, -77.507) #=> NOAA::Forecast containing next four days of forecast data for given coordinates
53
+ #
54
+ # <b>Note:</b> The NOAA updates this data no more than once an hour, and asks that users of the API not request the forecast
55
+ # for a given location more frequently than that. For more information, please see http://www.nws.noaa.gov/xml/#frequency
56
+ #
57
+ def forecast(num_days, lat, lng)
58
+ Forecast.from_xml(HttpService.new.get_forecast(num_days, lat, lng))
59
+ end
60
+ end
61
+ end
data/noaa.gemspec ADDED
@@ -0,0 +1,54 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{noaa}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Mat Brown"]
9
+ s.date = %q{2008-12-26}
10
+ s.default_executable = %q{noaa-update-stations}
11
+ s.description = %q{Ruby API for National Oceanic and Atmospheric Administration weather data}
12
+ s.email = %q{mat@patch.com}
13
+ s.executables = ["noaa-update-stations"]
14
+ s.extra_rdoc_files = ["lib/noaa/forecast.rb", "lib/noaa/http_service.rb", "lib/noaa/current_conditions.rb", "lib/noaa/station_writer.rb", "lib/noaa/station.rb", "lib/noaa/forecast_day.rb", "lib/noaa.rb", "bin/noaa-update-stations", "CHANGELOG", "README"]
15
+ s.files = ["lib/noaa/forecast.rb", "lib/noaa/http_service.rb", "lib/noaa/current_conditions.rb", "lib/noaa/station_writer.rb", "lib/noaa/station.rb", "lib/noaa/forecast_day.rb", "lib/noaa.rb", "Rakefile", "Manifest", "data/stations.yml", "bin/noaa-update-stations", "CHANGELOG", "test/test_station_writer.rb", "test/test_forecast.rb", "test/data/stations.xml", "test/data/stations-abridged.xml", "test/data/stations.yml", "test/data/KVAY.xml", "test/data/4-day.xml", "test/test_helper.rb", "test/test_station.rb", "test/test_http_service.rb", "test/test_current_conditions.rb", "README", "noaa.gemspec"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://github.com/outoftime/noaa}
18
+ s.post_install_message = %q{Be sure to update the weather station list:
19
+
20
+ noaa-update-stations
21
+
22
+ This can be run at any time to update the stations, but you must run it once to initially populate the station list.}
23
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Noaa", "--main", "README"]
24
+ s.require_paths = ["lib"]
25
+ s.rubyforge_project = %q{noaa}
26
+ s.rubygems_version = %q{1.3.1}
27
+ s.summary = %q{Ruby API for National Oceanic and Atmospheric Administration weather data}
28
+ s.test_files = ["test/test_station_writer.rb", "test/test_forecast.rb", "test/test_helper.rb", "test/test_station.rb", "test/test_http_service.rb", "test/test_current_conditions.rb"]
29
+
30
+ if s.respond_to? :specification_version then
31
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
32
+ s.specification_version = 2
33
+
34
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
35
+ s.add_runtime_dependency(%q<libxml-ruby>, [">= 0.9.7"])
36
+ s.add_runtime_dependency(%q<andre-geokit>, [">= 1.2.0"])
37
+ s.add_runtime_dependency(%q<jeremymcanally-context>, [">= 0.0.6"])
38
+ s.add_runtime_dependency(%q<jeremymcanally-matchy>, [">= 0.0.1"])
39
+ s.add_runtime_dependency(%q<ruby-debug>, ["~> 0.10"])
40
+ else
41
+ s.add_dependency(%q<libxml-ruby>, [">= 0.9.7"])
42
+ s.add_dependency(%q<andre-geokit>, [">= 1.2.0"])
43
+ s.add_dependency(%q<jeremymcanally-context>, [">= 0.0.6"])
44
+ s.add_dependency(%q<jeremymcanally-matchy>, [">= 0.0.1"])
45
+ s.add_dependency(%q<ruby-debug>, ["~> 0.10"])
46
+ end
47
+ else
48
+ s.add_dependency(%q<libxml-ruby>, [">= 0.9.7"])
49
+ s.add_dependency(%q<andre-geokit>, [">= 1.2.0"])
50
+ s.add_dependency(%q<jeremymcanally-context>, [">= 0.0.6"])
51
+ s.add_dependency(%q<jeremymcanally-matchy>, [">= 0.0.1"])
52
+ s.add_dependency(%q<ruby-debug>, ["~> 0.10"])
53
+ end
54
+ end
@@ -0,0 +1,116 @@
1
+ <?xml version="1.0"?>
2
+ <dwml version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.nws.noaa.gov/forecasts/xml/DWMLgen/schema/DWML.xsd">
3
+ <head>
4
+ <product srsName="WGS 1984" concise-name="dwmlByDay" operational-mode="official">
5
+ <title>NOAA's National Weather Service Forecast by 24 Hour Period</title>
6
+ <field>meteorological</field>
7
+ <category>forecast</category>
8
+ <creation-date refresh-frequency="PT1H">2008-12-23T21:46:52Z</creation-date>
9
+ </product>
10
+ <source>
11
+ <more-information>http://www.nws.noaa.gov/forecasts/xml/</more-information>
12
+ <production-center>Meteorological Development Laboratory<sub-center>Product Generation Branch</sub-center></production-center>
13
+ <disclaimer>http://www.nws.noaa.gov/disclaimer.html</disclaimer>
14
+ <credit>http://www.weather.gov/</credit>
15
+ <credit-logo>http://www.weather.gov/images/xml_logo.gif</credit-logo>
16
+ <feedback>http://www.weather.gov/feedback.php</feedback>
17
+ </source>
18
+ </head>
19
+ <data>
20
+ <location>
21
+ <location-key>point1</location-key>
22
+ <point latitude="40.72" longitude="-73.99"/>
23
+ </location>
24
+ <moreWeatherInformation applicable-location="point1">http://forecast.weather.gov/MapClick.php?textField1=40.72&amp;textField2=-73.99</moreWeatherInformation>
25
+ <time-layout time-coordinate="local" summarization="24hourly">
26
+ <layout-key>k-p24h-n4-1</layout-key>
27
+ <start-valid-time>2008-12-23T06:00:00-05:00</start-valid-time>
28
+ <end-valid-time>2008-12-24T06:00:00-05:00</end-valid-time>
29
+ <start-valid-time>2008-12-24T06:00:00-05:00</start-valid-time>
30
+ <end-valid-time>2008-12-25T06:00:00-05:00</end-valid-time>
31
+ <start-valid-time>2008-12-25T06:00:00-05:00</start-valid-time>
32
+ <end-valid-time>2008-12-26T06:00:00-05:00</end-valid-time>
33
+ <start-valid-time>2008-12-26T06:00:00-05:00</start-valid-time>
34
+ <end-valid-time>2008-12-27T06:00:00-05:00</end-valid-time>
35
+ </time-layout>
36
+ <time-layout time-coordinate="local" summarization="12hourly">
37
+ <layout-key>k-p12h-n8-2</layout-key>
38
+ <start-valid-time>2008-12-23T06:00:00-05:00</start-valid-time>
39
+ <end-valid-time>2008-12-23T18:00:00-05:00</end-valid-time>
40
+ <start-valid-time>2008-12-23T18:00:00-05:00</start-valid-time>
41
+ <end-valid-time>2008-12-24T06:00:00-05:00</end-valid-time>
42
+ <start-valid-time>2008-12-24T06:00:00-05:00</start-valid-time>
43
+ <end-valid-time>2008-12-24T18:00:00-05:00</end-valid-time>
44
+ <start-valid-time>2008-12-24T18:00:00-05:00</start-valid-time>
45
+ <end-valid-time>2008-12-25T06:00:00-05:00</end-valid-time>
46
+ <start-valid-time>2008-12-25T06:00:00-05:00</start-valid-time>
47
+ <end-valid-time>2008-12-25T18:00:00-05:00</end-valid-time>
48
+ <start-valid-time>2008-12-25T18:00:00-05:00</start-valid-time>
49
+ <end-valid-time>2008-12-26T06:00:00-05:00</end-valid-time>
50
+ <start-valid-time>2008-12-26T06:00:00-05:00</start-valid-time>
51
+ <end-valid-time>2008-12-26T18:00:00-05:00</end-valid-time>
52
+ <start-valid-time>2008-12-26T18:00:00-05:00</start-valid-time>
53
+ <end-valid-time>2008-12-27T06:00:00-05:00</end-valid-time>
54
+ </time-layout>
55
+ <time-layout time-coordinate="local" summarization="24hourly">
56
+ <layout-key>k-p4d-n1-3</layout-key>
57
+ <start-valid-time>2008-12-23T06:00:00-05:00</start-valid-time>
58
+ <end-valid-time>2008-12-27T06:00:00-05:00</end-valid-time>
59
+ </time-layout>
60
+ <parameters applicable-location="point1">
61
+ <temperature type="maximum" units="Fahrenheit" time-layout="k-p24h-n4-1">
62
+ <name>Daily Maximum Temperature</name>
63
+ <value>32</value>
64
+ <value>49</value>
65
+ <value>43</value>
66
+ <value>41</value>
67
+ </temperature>
68
+ <temperature type="minimum" units="Fahrenheit" time-layout="k-p24h-n4-1">
69
+ <name>Daily Minimum Temperature</name>
70
+ <value>31</value>
71
+ <value>41</value>
72
+ <value>33</value>
73
+ <value>39</value>
74
+ </temperature>
75
+ <probability-of-precipitation type="12 hour" units="percent" time-layout="k-p12h-n8-2">
76
+ <name>12 Hourly Probability of Precipitation</name>
77
+ <value>5</value>
78
+ <value>77</value>
79
+ <value>94</value>
80
+ <value>84</value>
81
+ <value>22</value>
82
+ <value>19</value>
83
+ <value>50</value>
84
+ <value>50</value>
85
+ </probability-of-precipitation>
86
+ <weather time-layout="k-p24h-n4-1">
87
+ <name>Weather Type, Coverage, and Intensity</name>
88
+ <weather-conditions weather-summary="Rain">
89
+ <value coverage="definitely" intensity="light" weather-type="rain" qualifier="none"/>
90
+ <value coverage="areas" intensity="none" additive="and" weather-type="fog" qualifier="none"/>
91
+ </weather-conditions>
92
+ <weather-conditions weather-summary="Rain">
93
+ <value coverage="definitely" intensity="light" weather-type="rain" qualifier="none"/>
94
+ <value coverage="areas" intensity="none" additive="and" weather-type="fog" qualifier="none"/>
95
+ </weather-conditions>
96
+ <weather-conditions weather-summary="Slight Chance Rain">
97
+ <value coverage="slight chance" intensity="light" weather-type="rain" qualifier="none"/>
98
+ </weather-conditions>
99
+ <weather-conditions weather-summary="Chance Rain">
100
+ <value coverage="chance" intensity="light" weather-type="rain" qualifier="none"/>
101
+ </weather-conditions>
102
+ </weather>
103
+ <conditions-icon type="forecast-NWS" time-layout="k-p24h-n4-1">
104
+ <name>Conditions Icons</name>
105
+ <icon-link>http://www.nws.noaa.gov/weather/images/fcicons/ra80.jpg</icon-link>
106
+ <icon-link>http://www.nws.noaa.gov/weather/images/fcicons/ra90.jpg</icon-link>
107
+ <icon-link>http://www.nws.noaa.gov/weather/images/fcicons/ra20.jpg</icon-link>
108
+ <icon-link>http://www.nws.noaa.gov/weather/images/fcicons/ra50.jpg</icon-link>
109
+ </conditions-icon>
110
+ <hazards time-layout="k-p4d-n1-3">
111
+ <name>Watches, Warnings, and Advisories</name>
112
+ <hazard-conditions xsi:nil="true"/>
113
+ </hazards>
114
+ </parameters>
115
+ </data>
116
+ </dwml>