00001
00002 #TODO In its infinite wisdom, the XML the NWS gives us (NWS-Stations.xml) is
00003 # not consistent wrt to lat lon. Some are in a +/- format, others in [NSEW]
00004 # format, also, some aren't even listed. It seems unlikely that the NWS doesn't
00005 # know that location of some of its weather stations and in fact they are on
00006 # their website, so maybe write a script to grab missing ones and massage them
00007 # all to a consistent format.
00008
00009 package NWSLocation;
00010 use English;
00011 use strict;
00012 use warnings;
00013
00014 require Exporter;
00015 use base qw(XML::SAX::Base);
00016 use XML::Parser;
00017 use Data::Dumper;
00018 use File::Basename;
00019 use Cwd 'abs_path';
00020
00021 our @ISA = qw(Exporter);
00022 our @EXPORT = qw(doSearch AddLatLonSearch AddStationIdSearch AddLocSearch);
00023 our $VERSION = 0.1;
00024
00025 my @latlonsearches;
00026 my @stationidsearches;
00027 my @locstrsearches;
00028 my @statesearches;
00029 my %currStation;
00030 my $searchresults;
00031
00032 sub doSearch {
00033 my $xml_file = dirname(abs_path($0 or $PROGRAM_NAME)) . "/NWS-Stations.xml";
00034
00035 my $parser = new XML::Parser( Style => 'Stream' );
00036 open(XML, $xml_file) or die "cannot open NWS-Stations.xml file\n";
00037 $parser->parse(*XML);
00038 close(XML);
00039 return $searchresults;
00040 }
00041
00042 sub StartDocument {
00043 my $expat = shift;
00044
00045 $expat->{finish} = 0;
00046
00047 }
00048
00049 sub StartTag {
00050 my ($expat, $name, %atts) = @_;
00051
00052 if ($name eq 'station') {
00053 $expat->{CurrEntry} = {};
00054 $expat->{MatchFound} = 0;
00055 }
00056 }
00057
00058 sub Text {
00059
00060 my $expat = shift;
00061 my $text = $expat->{Text};
00062 my $search;
00063
00064 if ($expat->in_element('station_id')) {
00065 $expat->{CurrEntry}->{station_id} = $text;
00066 if (!$expat->{MatchFound}) {
00067 foreach $search (@stationidsearches) {
00068 if ($text =~ m/$search/i) {
00069 $expat->{MatchFound} = 1;
00070 return;
00071 }
00072 }
00073 }
00074 }
00075
00076 if ($expat->in_element('state')) {
00077 $expat->{CurrEntry}->{state} = $text;
00078 if (!$expat->{MatchFound}) {
00079 foreach $search (@statesearches) {
00080 if ($text =~ m/$search/i) {
00081 $expat->{MatchFound} = 1;
00082 return;
00083 }
00084 }
00085 }
00086 }
00087
00088 if ($expat->in_element('station_name')) {
00089 $expat->{CurrEntry}->{station_name} = $text;
00090 if (!$expat->{MatchFound}) {
00091 foreach $search (@locstrsearches) {
00092 if ($text =~ m/$search/i) {
00093 $expat->{MatchFound} = 1;
00094 return;
00095 }
00096 }
00097 }
00098 }
00099
00100 # annoyingly, the lat/lon format is not consistent in the XML file,
00101 # sometimes its in +/- format, other times N/S E/W, so we convert it right
00102 # off to be unifrom in +/-
00103 if ($expat->in_element('latitude')){
00104 $text =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[N]/+$1/ or
00105 $text =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[S]/-$1/;
00106 $expat->{CurrEntry}->{latitude} = $text;
00107 $expat->{currLat} = $text;
00108 return;
00109 }
00110
00111 if ($expat->in_element('longitude')) {
00112 $text =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[E]/+$1/ or
00113 $text =~ s/(\d{1,3}([.]\d{1,3})?)([.]\d{1,3})?[W]/-$1/;
00114 $expat->{CurrEntry}->{longitude} = $text;
00115 if (!$expat->{MatchFound}) {
00116 foreach $search (@latlonsearches) {
00117 if ($search->[0] eq $expat->{currLat} && $search->[1] eq $text) {
00118 $expat->{MatchFound} = 1;
00119 return;
00120 }
00121 }
00122 }
00123 }
00124 }
00125
00126 sub EndTag {
00127 my ($expat, $name) = @_;
00128
00129 if ($name eq 'station' && $expat->{MatchFound}) {
00130 push (@$searchresults, $expat->{CurrEntry});
00131 if ($expat->{finish}) {
00132 $expat->finish();
00133 return;
00134 }
00135 }
00136
00137 }
00138
00139 sub AddLatLonSearch {
00140 my ($lat, $lon) = @_;
00141 push (@latlonsearches, [$lat, $lon]);
00142 }
00143
00144 sub AddStationIdSearch {
00145 my $id = shift;
00146 push (@stationidsearches, $id);
00147 }
00148
00149 sub AddLocSearch {
00150 my $loc = shift;
00151 push (@locstrsearches, $loc);
00152 }
00153
00154 sub AddStateSearch {
00155 my $state = shift;
00156 push (@statesearches, $state);
00157 }
00158
00159 1;