File Coverage

blib/lib/WWW/MapBlast.pm
Criterion Covered Total %
statement 15 65 23.0
branch 0 34 0.0
condition 0 37 0.0
subroutine 5 8 62.5
pod 0 3 0.0
total 20 147 13.6


line stmt bran cond sub pod time code
1             package WWW::MapBlast;
2             our $VERSION = 0.02;
3             our $DATE = "Mon Jun 25 18:13:00 2001 BST";
4            
5 1     1   6293 use LWP::UserAgent;
  1         51186  
  1         35  
6 1     1   12 use HTTP::Request;
  1         2  
  1         24  
7 1     1   1005 use HTML::TokeParser;
  1         12787  
  1         30  
8 1     1   8 use strict;
  1         2  
  1         23  
9 1     1   4 use warnings;
  1         1  
  1         1467  
10            
11             =head1 NAME
12            
13             WWW::MapBlast - latitude & longitude from postal codes.
14            
15             =head1 SYNOPSIS
16            
17             use WWW::MapBlast;
18             my ($lat, $lon) = WWW::MapBlast::latlon('United Kingdom','BN3 3AG');
19             __END__;
20            
21             =head1 DESCRIPTION
22            
23             Simply accesses L and
24             retrieves latitude and longitude information.
25            
26             Only minimal error checking, so have a look through the source before you use.
27            
28             =cut
29            
30             our %countriesList = (
31             "United States"=>"USA","AFG"=>"Afghanistan","Albania"=>"ALB","Algeria"=>"DZA",
32             "American Samoa"=>"ASM","Andorra"=>"AND","Angola"=>"AGO","Anguilla"=>"AIA",
33             "Antigua and Barbuda"=>"ATG","Argentina"=>"ARG","Armenia"=>"ARM","Aruba"=>"ABW",
34             "Australia"=>"AUS","Austria"=>"AUT","Azerbaijan"=>"AZE","Bahamas"=>"BHS",
35             "Bahrain"=>"BHR","Bangladesh"=>"BGD","Barbados"=>"BRB","Belarus"=>"BLR",
36             "Belgium"=>"BEL","Belize"=>"BLZ","Benin"=>"BEN","Bermuda"=>"BMU",
37             "Bhutan"=>"BTN","Bolivia"=>"BOL","Bosnia and Herzegovina"=>"BIH","Botswana"=>"BWA",
38             "Brazil"=>"BRA","British Virgin Islands"=>"VGB","Brunei Darussalam"=>"BRN",
39             "Bulgaria"=>"BGR","Burkina Faso"=>"BFA","Burundi"=>"BDI","Cambodia"=>"KHM",
40             "Cameroon"=>"CMR","Canada"=>"CAN","Cape Verde"=>"CPV","Cayman Islands"=>"CYM",
41             "Central African Republic"=>"CAF","Chad"=>"TCD",
42             "Chile"=>"CHL","China"=>"CHN","Colombia"=>"COL","Comoros"=>"COM",
43             "Congo"=>"COG","Cook Islands"=>"COK","Costa Rica"=>"CRI","Croatia"=>"HRV",
44             "Cuba"=>"CUB","Cyprus"=>"CYP","Czech Republic"=>"CZE","Denmark"=>"DNK",
45             "Djibouti"=>"DJI","Dominica"=>"DMA","Dominican Republic"=>"DOM","Ecuador"=>"ECU",
46             "Egypt"=>"EGY","El Salvador"=>"SLV","Equatorial Guinea"=>"GNQ","Eritrea"=>"ERI",
47             "Estonia"=>"EST","Ethiopia"=>"ETH","Falkland Islands"=>"FLK","Faroe Islands"=>"FRO",
48             "Fiji"=>"FJI","Finland"=>"FIN","France"=>"FRA","French Guiana"=>"GUF",
49             "French Polynesia"=>"PYF","Gabon"=>"GAB","Gambia"=>"GMB","Georgia"=>"GEO",
50             "Germany"=>"DEU","Ghana"=>"GHA","Gibraltar"=>"GIB","Greece"=>"GRC",
51             "Greenland"=>"GRL","Grenada"=>"GRD","Guadeloupe"=>"GLP","Guatemala"=>"GTM",
52             "Guinea"=>"GIN","Guinea Bissau"=>"GNB","Guyana"=>"GUY","Haiti"=>"HTI",
53             "Honduras"=>"HND","Hong Kong"=>"HKG","Hungary"=>"HUN","Iceland"=>"ISL",
54             "India"=>"IND","Indonesia"=>"IDN","Iran"=>"IRN","Iraq"=>"IRQ",
55             "Ireland"=>"IRL","Israel"=>"ISR","Italy"=>"ITA","Ivory Coast"=>"CIV",
56             "Jamaica"=>"JAM","Japan"=>"JPN","Jordan"=>"JOR","Kazakhstan"=>"KAZ",
57             "Kenya"=>"KEN","Kiribati"=>"KIR","Kuwait"=>"KWT","Kyrgyzstan"=>"KGZ",
58             "Laos"=>"LAO","Latvia"=>"LVA","Lebanon"=>"LBN","Lesotho"=>"LSO",
59             "Liberia"=>"LBR","Libya"=>"LBY",",Liechtenstein"=>"LIE","Lithuania"=>"LTU",
60             "Luxembourg"=>"LUX","Macau"=>"MAC","Macedonia"=>"MKD","Madagascar"=>"MDG",
61             "Malawi"=>"MWI","Malaysia"=>"MYS","Maldives"=>"MDV","Mali"=>"MLI",
62             "Malta"=>"MLT","Marshall Islands"=>"MHL","Martinique"=>"MTQ","Mauritania"=>"MRT",
63             "Mauritius"=>"MUS","Mexico"=>"MEX","Micronesia"=>"FSM","Moldova"=>"MDA",
64             "Monaco"=>"MCO","Mongolia"=>"MNG","Montserrat"=>"MSR","Morocco"=>"MAR",
65             "Mozambique"=>"MOZ","Myanmar"=>"MMR","Namibia"=>"NAM","Nepal"=>"NPL",
66             "Netherlands"=>"NLD","Netherlands Antilles"=>"ANT","New Caledonia"=>"NCL","New Zealand"=>"NZL",
67             "Nicaragua"=>"NIC","Niger"=>"NER","Nigeria"=>"NGA","Norfolk Island"=>"NFK",
68             "North Korea"=>"PRK","Northern Mariana Islands"=>"MNP","Norway"=>"NOR","Oman"=>"OMN",
69             "Pakistan"=>"PAK","Palau"=>"PLW","Panama"=>"PAN","Papua New Guinea"=>"PNG",
70             "Paraguay"=>"PRY","Peru"=>"PER","Philippines"=>"PHL","Poland"=>"POL",
71             "Portugal"=>"PRT","Puerto Rico"=>"PRI","Qatar"=>"QAT","Reunion"=>"REU",
72             "Romania"=>"ROM","Russia"=>"RUS","Rwanda"=>"RWA","Saint Helena"=>"SHN",
73             "Saint Kitts and Nevis"=>"KNA","Saint Lucia"=>"LCA","Saint Pierre and Miquelon"=>"SPM","Saint Vincent/Grenadines"=>"VCT","Samoa"=>"WSM","San Marino"=>"SMR",
74             "Saotome and Principe"=>"STP","Saudi Arabia"=>"SAU","Senegal"=>"SEN","Seychelles"=>"SYC",
75             "Sierra Leone"=>"SLE","Singapore"=>"SGP","Slovak Republic"=>"SVK","Slovenia"=>"SVN",
76             "Solomon Islands"=>"SLB","Somalia"=>"SOM","South Africa"=>"ZAF","South Korea"=>"KOR",
77             "Spain"=>"ESP","Sri Lanka"=>"LKA","Sudan"=>"SDN","Suriname"=>"SUR",
78             "Swaziland"=>"SWZ","Sweden"=>"SWE","Switzerland"=>"CHE","Syria"=>"SYR",
79             "Taiwan"=>"TWN","Tajikistan"=>"TJK","Tanzania"=>"TZA","Thailand"=>"THA",
80             "Togo"=>"TGO","Tokelau"=>"TKL","Tonga"=>"TON","Trinidad and Tobago"=>"TTO",
81             "Tunisia"=>"TUN","Turkey"=>"TUR","Turkmenistan"=>"TKM","Turks and Caicos Islands"=>"TCA",
82             "Uganda"=>"UGA","Ukraine"=>"UKR","United Arab Emirates"=>"ARE","United Kingdom"=>"GBR",
83             "United States"=>"USA","US Virgin Islands"=>"VIR","Uruguay"=>"URY","Uzbekistan"=>"UZB",
84             "Vanuatu"=>"VUT","Vatican"=>"VAT","Venezuela"=>"VEN","Vietnam"=>"VNM",
85             "Western Sahara"=>"ESH","Yemen"=>"YEM","Yugoslavia"=>"YUG","Zambia"=>"ZMB",
86             "Zimbabwe"=>"ZWE"
87             );
88            
89            
90             =head1 Commentary
91            
92             Set $CHAT if you wish to see what's going on during net access.
93            
94             =cut
95            
96             our $CHAT;
97            
98             =head1 Subroutine latlon (country, postcode)
99            
100             Accepts a country name and a postal code, returns the relative latitude and longitude as defined by MapBlast.com
101            
102             The argument C must match a key of the module's C<%countriesList> hash, so it may be an idea to check your input against those keys before calling.
103            
104             Will try to connect four times, and return C on failure.
105            
106             B that latitude and longitude is not (C,C) !
107            
108             =cut
109            
110 0     0 0   sub latlon { my ($country, $postcode) = (shift,shift);
111 0           for (0..3){
112 0 0         warn "Trying $_...\n" if $CHAT;
113 0           my $doc = get_document($country,$postcode);
114 0           @_ = extract_latlon($doc);
115 0 0         last if defined $_[0];
116             }
117 0           return @_;
118             }
119            
120            
121             #
122             # SUB get_document
123             # Accepts a country name, and a postcode
124             # Returns:
125             #
126 0     0 0   sub get_document { my ($country,$postcode) = (shift,shift);
127 0 0 0       die "get_document requires a \$country,\$postcode arrity" if not defined $country or not defined $postcode;
128 0 0 0       warn "No code for country <$country>." and return undef if not exists $countriesList{$country};
129 0           $postcode =~ s/\s//g;
130            
131 0           my $ua = LWP::UserAgent->new; # Create a new UserAgent
132 0           $ua->agent('Mozilla/25.'.(localtime)." (PERL __PACKAGE__ $VERSION"); # Give it a type name
133 0 0         warn "Attempting to access ...\n" if $CHAT;
134            
135 0           my $url =
136             'http://www.mapblast.com/myblast/map.mb?'
137             . 'CMD=GEO&req_action=crmap&AD4='. $countriesList{$country}
138             . '&AD3='.$postcode
139             . '&x=0&y=0';
140            
141             # Format URL request
142 0 0 0       my $req = new HTTP::Request ('GET',$url) or die "...could not GET.\n" and return undef;
143 0           my $res = $ua->request($req); # $res is the object UA returned
144 0 0         if (not $res->is_success()) { # If successful
145 0 0         warn"...failed.\n" if $CHAT;
146             return undef
147 0           }
148 0 0         warn "...ok.\n" if $CHAT;
149            
150 0           return $res->content;
151             }
152            
153            
154             #
155             # extract_latlon
156             # Accepts an HTML result page from a MapBlast.com search
157             # Extracts the latitude/longitude from a link within the page
158             # - such as http://www.mapblast.com/myblast/driveSilo.mb?&IC_2=51.592423:-0.171996:8:&CT_2=51.592423:-0.171995:20000&AD4_2=GBR&apmenu_2=&apcode_2=&GAD1_2=&GAD2_2=Leslie+Road&GAD3_2=London%2c+N2+8BH&GMI_2=&MA=1&phone_2="
159             # Retunrs lat/lon, and the address as three scalars
160             #
161 0     0 0   sub extract_latlon { my $doc = shift;
162 0           my $token;
163 0           my $address = ' ';
164 0 0         my $p = HTML::TokeParser->new(\$doc) or die "Couldn't create TokePraser: $!";
165            
166             # Get the address
167 0           while ($token = $p->get_token){
168 0 0 0       if (@$token[1] eq 'input'
  0   0        
      0        
      0        
      0        
169             and defined @$token[2]
170 0           and exists %{@$token[2]}->{name}
171 0           and exists %{@$token[2]}->{value}
172 0           and %{@$token[2]}->{name} =~ /^GAD\d$/
173             and %{@$token[2]}->{value} !~ m/^\s*$/
174             ){
175 0           $_ = %{@$token[2]}->{value};
  0            
176 0 0 0       if (defined $address and $address !~ m/$_/i){
177 0           $address .= "$_,";
178             }
179             }
180             }
181 0 0         $address = substr( $address, 1, length($address)-2 ) if defined $address;
182 0           $address =~ s/,+(\w)/, $1/g; # MapBlast returns ugly lists
183 0 0 0       return "Address not found" if not defined $address and $doc=~/Address not found/i;
184            
185             # Get the co-ords
186 0 0         $p = HTML::TokeParser->new(\$doc) or die "Couldn't create TokePraser: $!";
187 0   0       while ($token = $p->get_token
      0        
188             and not (@$token[1] eq 'img' and %{@$token[2]}->{src} eq '/myblast/images/topnav/mapsiloon.gif')
189             ){}
190 0   0       while ($token = $p->get_token and @$token[1] ne 'a'){}
191 0 0         if (defined @$token[2]){
192 0           %{@$token[2]}->{href} =~ m/IC_2=([\d:.-]+)&/;
  0            
193 0 0         if (defined $1){
194 0           my ($lat,$lon,$rubbish) = split(/:/,$1,3);
195 0           return ($lat,$lon,$address);
196             }
197             }
198 0           warn "Unexpected format from MapBlast.com.\n";
199 0           return undef;
200             }
201            
202            
203             =head1 LATITUDE AND LONGITUDE
204            
205             After L:
206            
207             =over 4
208            
209             Zero degrees latitude is the equator, with the North pole at 90 degrees latitude and the South pole at -90 degrees latitude.
210             one degree is approximately 69 miles. Greenwich, England is at 51.466 degrees north of the equator.
211            
212             Zero degrees longitude goes through Greenwich, England.
213             Again, Each 69 miles from this meridian represents approximately 1 degree of longitude.
214             East/West is plus/minus respectively.
215            
216             =back
217            
218             =head1 PREREQUISITES
219            
220             LWP::UserAgent;
221             HTTP::Request;
222             HTML::TokeParser;
223             strict;
224             warnings.
225            
226             =head1 EXPORTS
227            
228             None by default.
229            
230             =head1 REVISIONS
231            
232             =item 0.02
233            
234             Now returns street addresses in addition to latitude and longitude.
235            
236             =head1 SEE ALSO
237            
238             L, L, L.
239            
240             =head1 AUTHOR
241            
242             Lee Goddard L.
243            
244             =head1 COPYRIGHT
245            
246             Copyright (C) Lee Goddard, 2001 - All Rights Reserved.
247            
248             This library is free software and may be used only under the same terms as Perl itself.
249            
250             =cut
251            
252             1;
253             __END__