3 # TODO handle xsi:nil="true" handling
4 # TODO can soap data be received as stream, so we don't have to store giant string?
5 # TODO cache SOAP response with all data, and only update that occasionally, to
6 # prevent hammering the NWS servers, also, to speed up the scripts.
7 # TODO is visibility handling right? Have never seen it not nil, so I don't know
8 # what its going to look like. Update: I think nil means unlimited from looking
9 # at table 7 in http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.htm, still
10 # waiting to get something other than nil though.
15 use base qw(XML::SAX::Base);
19 our @ISA = qw(Exporter);
20 our @EXPORT = qw(doParse);
29 ########### Parsing Methods ##################
32 my ($expat, $name, %atts) = @_;
34 if ($name eq 'time-layout') {
35 $expat->setHandlers( Start => \&timeStart, Char => \&timeChar );
39 if ($name eq 'parameters') {
40 $expat->setHandlers( Start => \&weatherStart, End => \&weatherEnd, Char => \&weatherChar );
45 my ($expat, $name, %atts) = @_;
46 if ($name eq 'time-layout') {
47 $timelayout{$currKey} = $currtimearray;
48 $expat->{CurrDay} = 0;
49 $expat->{CurrNight} = 0;
50 undef $expat->{TimeDate};
51 $expat->setHandlers( Char => \&Text, Start => \&StartTag );
59 if ($expat->in_element('creation-date')) {
60 $creationdate = $expat->{Text};
65 my ($expat, $name, %atts) = @_;
70 my ($expat, $name, %atts) = @_;
72 if ($name eq 'value') {
73 $timestr = $currtimearray->[$expat->{timeindex}];
75 foreach $attr (keys(%atts)) {
76 $condhash->{$attr} = $atts{$attr};
78 push @{$weatherdata{$timestr}->{$currLbl}}, $condhash;
81 if ($name eq 'visibility') {
82 $timestr = $currtimearray->[$expat->{timeindex}];
83 $index = $#{$weatherdata{$timestr}->{$currLbl}};
84 if ($atts{'xsi:nil'}) {
85 $weatherdata{$timestr}->{$currLbl}->[$index]->{visibility} =
92 my ($expat, $text) = @_;
93 if ($expat->in_element('visibility')) {
94 $timestr = $currtimearray->[$expat->{timeindex}];
95 $weatherdata{$timestr}->{$currLbl}->{visibility} = $text;
100 my ($expat, $name) = @_;
102 if ($name eq 'weather') {
103 $expat->setHandlers( Start => \&weatherStart,
104 End => \&weatherEnd, Char => \&weatherChar );
106 if ($name eq 'weather-conditions') {
107 $expat->{timeindex}++;
112 my ($expat, $name, %atts) = @_;
114 if ($expat->in_element('parameters')) {
117 $currLbl .= "_$atts{type}";
119 $currtimearray = $timelayout{$atts{'time-layout'}};
120 $expat->{timeindex} = 0;
122 if ($name eq 'weather') {
123 $expat->setHandlers( Start => \&conditionsStart,
124 End =>\&conditionsEnd, Char => \&conditionsChar);
131 my ($expat, $name, %atts) = @_;
132 if ($name eq 'parameters') {
133 $expat->setHandlers( Char=> \&Text, Start => \&StartTag );
139 my ($expat, $text) = @_;
140 if ($expat->in_element('value') || $expat->in_element('icon-link')) {
141 $timestr = $currtimearray->[$expat->{timeindex}++];
142 $weatherdata{$timestr}->{$currLbl} = $text;
152 my ($expat, $text) = @_;
153 if ($expat->in_element('layout-key')) {
158 if ($expat->in_element('start-valid-time')) {
159 # yea, putting it into almost the same format, the reason for this that
160 # you can't get a date out of UnixDate that has tz in 0:00 format,
162 $text = UnixDate($text, "%O%z");
163 if ($currKey =~ /p3h/) {
164 push (@$currtimearray, $text);
166 $expat->{CurrStartTime} = $text;
168 if ($expat->in_element('end-valid-time')) {
169 $text = UnixDate($text, "%O%z");
170 if ($currKey !~ /p3h/) {
171 push (@$currtimearray, "$expat->{CurrStartTime},$text");
177 ########## Exported method to do parsing #################
180 my ($lat, $lon, $start, $end, $units, $params) = @_;
181 my $product = "time-series";
183 my $NDFD_XML = ndfdXML->NDFDgen(SOAP::Data->name("latitude" => $lat),
184 SOAP::Data->name("longitude" => $lon),
185 SOAP::Data->name("product" => $product),
186 SOAP::Data->name("startTime" => $start),
187 SOAP::Data->name("endTime" => $end),
188 SOAP::Data->name("Unit" => $units),
189 SOAP::Data->name("weatherParameters" =>
191 SOAP::Data->type('boolean')->name("maxt" => $params->{maxt}),
192 SOAP::Data->type('boolean')->name("mint" => $params->{mint}),
193 SOAP::Data->type('boolean')->name("temp" => $params->{temp}),
194 SOAP::Data->type('boolean')->name("dew" => $params->{dew}),
195 SOAP::Data->type('boolean')->name("pop12" => $params->{pop12}),
196 SOAP::Data->type('boolean')->name("qpf" => $params->{qpf}),
197 SOAP::Data->type('boolean')->name("sky" => $params->{sky}),
198 SOAP::Data->type('boolean')->name("snow" => $params->{snow}),
199 SOAP::Data->type('boolean')->name("wspd" => $params->{wspd}),
200 SOAP::Data->type('boolean')->name("wdir" => $params->{wdir}),
201 SOAP::Data->type('boolean')->name("wx" => $params->{wx}),
202 SOAP::Data->type('boolean')->name("waveh" => $params->{waveh}),
203 SOAP::Data->type('boolean')->name("icons" => $params->{icons}),
204 SOAP::Data->type('boolean')->name("rh" => $params->{rh}),
205 SOAP::Data->type('boolean')->name("appt" => $params->{appt}))));
207 my $parser = new XML::Parser(Style => 'Stream');
208 $parser->parse("$NDFD_XML");
209 return (\%weatherdata, $creationdate);