00001 # This script parses the XML of an Environment Canada weather forecast
00002 # page as returned from http://www.weatheroffice.gc.ca.
00003 #
00004 # TODO Environment Canada only reports 5 day forecasts. 6 day forecast
00005 # layout is used to report 5 day information.
00006 #
00007 # This requires the XML::Simple module.
00008
00009 package ENVCANParser;
00010 use strict;
00011 use POSIX;
00012 use XML::Simple;
00013
00014 our $VERSION = 0.4;
00015
00016 my %results;
00017 my %directions = ( N => "North", NNE => "North Northeast",
00018 S => "South", ENE => "East Northeast",
00019 E => "East", ESE => "East Southeast",
00020 W => "West", SSE => "South Southeast",
00021 NE => "Northeast", SSW => "South Southwest",
00022 NW => "Northwest", WSW => "West Southwest",
00023 SE => "Southeast", WNW => "West Northwest",
00024 SW => "Southwest", NNW => "North Northwest");
00025
00026 sub getIcon {
00027 my $condition = shift;
00028 my $icon;
00029
00030 if ( ($condition =~ /snow/i) || ($condition =~ /flurries/i)) {
00031 $icon = 'flurries.png';
00032 $icon = 'rainsnow.png' if ($condition =~ /rain/i);
00033 $icon = 'snowshow.png' if ($condition =~ /heavy/i);
00034 }
00035 elsif ($condition =~ /fog/i) {
00036 $icon = 'fog.png';
00037 }
00038 elsif ($condition =~ /drizzle/i) {
00039 $icon = 'lshowers.png';
00040 $icon = 'rainsnow.png' if ($condition =~ /freezing/i);
00041 }
00042 elsif ( ($condition =~ /rain/i) || ($condition =~ /showers/i) ) {
00043 $icon = 'showers.png';
00044 $icon = 'lshowers.png' if ( ($condition =~ /chance/i) ||
00045 ($condition =~ /few/i));
00046 $icon = 'rainsnow.png' if ( ($condition =~ /snow/i) ||
00047 ($condition =~ /flurries/i));
00048 $icon = 'thunshowers.png' if ($condition =~ /thunder/i);
00049 }
00050 elsif ($condition =~ /cloud/i) {
00051 $icon = 'cloudy.png';
00052 $icon = 'mcloudy.png' if ($condition =~ /mostly/i);
00053 $icon = 'pcloudy.png' if ( ($condition =~ /few/i) ||
00054 ($condition =~ /mix/i) ||
00055 ($condition =~ /partly/i) ||
00056 ($condition =~ /period/i) );
00057 }
00058 elsif ($condition =~ /clear/i) {
00059 $icon = 'fair.png';
00060 }
00061 elsif ($condition =~ /sun/i) {
00062 $icon = 'sunny.png';
00063 }
00064 else {
00065 $icon = 'unknown.png';
00066 }
00067
00068 return $icon;
00069 }
00070
00071 sub doParse {
00072
00073 my ($data, @types) = @_;
00074
00075 # Initialize results hash
00076 foreach my $type (@types) { $results{$type} = ""; }
00077
00078 my $xml = XMLin($data);
00079 die if (!$xml);
00080
00081 $results{'copyright'} = $xml->{channel}->{copyright};
00082 if ($xml->{channel}->{title} =~ /^(.*) - Weather/) {
00083 $results{'cclocation'} = ucfirst($1);
00084 $results{'3dlocation'} = ucfirst($1);
00085 $results{'6dlocation'} = ucfirst($1);
00086 }
00087
00088 my $i = 0;
00089 foreach my $item (@{$xml->{channel}->{item}}) {
00090 if ($item->{title} =~ /Current Conditions/) {
00091 if ($item->{description} =~ /Condition:\<\/b\>\s*([\w ]*)\s*\<br\/\>/s) {
00092 $results{'weather'} = $1;
00093 $results{'weather_icon'} = getIcon($1);
00094 }
00095 $results{'temp'} = sprintf("%.0f", $1)
00096 if ($item->{description} =~ /Temperature:\<\/b\>\s*(-?\d*\.?\d*)\260\C\s*\<br\/\>/s);
00097 $results{'pressure'} = sprintf("%d", $1 * 10)
00098 if ($item->{description} =~ /Pressure \/ Tendency:\<\/b\>\s*(\d*\.?\d*) kPa\s*.*\<br\/\>/s);
00099 $results{'visibility'} = sprintf("%.1f", $1)
00100 if ($item->{description} =~ /Visibility:\<\/b\>\s*(\d*\.?\d*) km\s*.*\<br\/\>/s);
00101 $results{'relative_humidity'} = $1
00102 if ($item->{description} =~ /Humidity:\<\/b\>\s*(\d*) \%\<br\/\>/s);
00103 if ($item->{description} =~ /Wind Chill:\<\/b\>\s*(-?\d*\.?\d*)\s*\<br\/\>/s) {
00104 $results{'appt'} = $1;
00105 $results{'windchill'} = $1;
00106 }
00107 $results{'dewpoint'} = sprintf("%.0f", $1)
00108 if ($item->{description} =~ /Dewpoint:\<\/b\>\s*(-?\d*\.?\d*)\260\C\s*\<br\/\>/s);
00109 if ($item->{description} =~ /(\d*\:\d*[\w ]*\d*[\w *]\d*)\s*\<br\/\>/s) {
00110 $results{'observation_time'} = "Last updated at ". $1;
00111 $results{'updatetime'} = "Last updated at ". $1;
00112 }
00113 if ($item->{description} =~ /Wind:\<\/b\>(.*)\<br\/\>/s) {
00114 my $wind = $1;
00115 if ($wind =~ /\s*(\d*)\s*km\/h\s*/i) {
00116 $results{'wind_dir'} = 'Calm';
00117 $results{'wind_speed'} = $1;
00118 $results{'wind_gust'} = 0;
00119 }
00120 if ($wind =~ /\s*(\w*)\s*(\d*)\s*km\/h\s*/i) {
00121 $results{'wind_dir'} = $directions{$1};
00122 $results{'wind_speed'} = $2;
00123 }
00124 if ($wind =~ /\s*(\w*)\s*(\d*)\s*km\/h\s*gust\s*(\d*)\s*km\/h/i) {
00125 $results{'wind_gust'} = $3;
00126 }
00127 }
00128 next;
00129 }
00130
00131 if ($item->{title} =~ /^(.*):\s*([\w ]*)\.\s*(.*)/) {
00132 my $day = $1;
00133 my $condition = $2;
00134 my $high_low = $3;
00135 my $temp;
00136
00137 $results{"date-$i"} = $day;
00138 $results{"icon-$i"} = getIcon($condition);
00139
00140 if ($high_low =~ /high ([a-z]*)\s?(\d*)/i) {
00141 $temp = $2;
00142 if ($1 =~ /minus/i) { $temp = ($temp * -1); }
00143 $results{"high-$i"} = $temp;
00144 }
00145
00146 if ($high_low =~ /steady near ([a-z]*)\s?(\d*)/i) {
00147 $temp = $2;
00148 if ($1 =~ /minus/i) { $temp = ($temp * -1); }
00149 $results{"high-$i"} = $temp;
00150 }
00151
00152 if ($high_low =~ /low ([a-z]*)\s?(\d*)/i) {
00153 $temp = $2;
00154 if ($1 =~ /minus/i) { $temp = ($temp * -1); }
00155 $results{"low-$i"} = $temp;
00156 }
00157
00158 $results{"high-$i"} = 0 if ($high_low =~ /high zero/i);
00159 $results{"low-$i"} = 0 if ($high_low =~ /low zero/i);
00160
00161 $i++;
00162 }
00163 }
00164
00165 # Correct for Environment Canada's temperature methods
00166 $results{'low-0'} = $results{'low-1'} if (!length($results{'low-0'}));
00167 $results{'low-1'} = $results{'low-0'} if (!length($results{'low-1'}));
00168 $results{'low-2'} = $results{'low-1'} if (!length($results{'low-2'}));
00169 $results{'low-3'} = $results{'low-4'} if (!length($results{'low-3'}));
00170 $results{'high-0'} = $results{'temp'} if (!length($results{'high-0'}) &&
00171 ($results{'temp'} >= $results{'low-0'}));
00172 $results{'high-1'} = $results{'high-0'} if (!length($results{'high-1'}));
00173 $results{'high-2'} = $results{'high-1'} if (!length($results{'high-2'}));
00174
00175 return %results;
00176 }
00177
00178 1