Changeset 403
- Timestamp:
- Dec 3, 2006, 5:29:41 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/npemap.org.uk/cgi/geocoder.fcgi
r402 r403 2 2 # Looks up a location for a given postcode, returning the closest we have, 3 3 # and an idea of how accurate a match we found. 4 # Can return plain text, or XML 4 # Looks up the nearest postcode for a given location, optionally returning 5 # the several nearest (rather than just the nearest) 6 # Looks up the nearest postcode area for a given location, optionally 7 # returning the several nearest (rather than just the nearest) 8 # 9 # Can return plain text, JS, JS callback, or XML 5 10 # 6 11 # TODO: Make me more generic, so I can work on the portal site 7 12 # 8 # Copyright (c) 2006 Dominic Hargreaves 13 # Copyright (c) 2006 Dominic Hargreaves, Nick Burch and David Sheldon 9 14 # See accompanying file "LICENCE" for licence details 10 15 … … 71 76 } 72 77 78 # How many results did they want? 79 # (Not all searches support more than one result) 80 my $limit_results = 1; 81 if(defined $cgi->param("results")) { 82 $limit_results = $cgi->param("results"); 83 unless($limit_results =~ /^\d+$/) { 84 print_err ("Invalid maximum number of results '$limit_results' supplied"); 85 next REQUEST; 86 } 87 } 88 89 73 90 # Did they want to do postcode -> location, or location -> postcode? 91 my %request; 92 my @results; 74 93 75 94 # What postcode were they asking about? 76 my $postcode;77 my $outward;78 my $inward;79 95 if(defined $cgi->param("postcode")) { 80 $postcode = uc($cgi->param("postcode")); 81 ($outward,$inward) = ($postcode =~ /^([A-Z]+\d+[A-Z]?)\s*(\d[A-Z][A-Z])?$/); 82 unless($outward) { 83 print_err ("Invalid postcode '$postcode' supplied"); 96 $limit_results = 1; 97 $request{type} = "location"; 98 99 $request{postcode} = uc($cgi->param("postcode")); 100 ($request{outward},$request{inward}) = 101 ($request{postcode} =~ /^([A-Z]+\d+[A-Z]?)\s*(\d[A-Z][A-Z])?$/); 102 103 unless($request{outward}) { 104 print_err ("Invalid postcode '".$request{postcode}."' supplied"); 84 105 next REQUEST; 85 106 } 107 } elsif(defined $cgi->param("easting") && defined $cgi->param("northing")) { 108 $request{type} = "postcode"; 109 $request{easting} = $cgi->param("easting"); 110 $request{northing} = $cgi->param("northing"); 111 112 if( (defined $cgi->param("area") && $cgi->param("area")) || 113 (defined $cgi->param("areas") && $cgi->param("areas")) ) { 114 $request{type} = "area"; 115 } 116 117 unless($request{easting} =~ /^\d+$/) { 118 print_err ("Invalid easting '".$request{easting}."' supplied"); 119 next REQUEST; 120 } 121 unless($request{northing} =~ /^\d+$/) { 122 print_err ("Invalid northing '".$request{northing}."' supplied"); 123 next REQUEST; 124 } 86 125 } else { 87 print_err (" Required parameter 'postcode' not supplied");126 print_err ("You must either supply the parameter 'postcode', or the two parameters 'easting' and 'northing'"); 88 127 next REQUEST; 89 128 } 90 129 91 130 92 my ($easting,$northing,$matched,$pc); 93 94 # Work out until we find a match 95 ($easting,$northing,$matched,$pc) = execute($full_matcher,$outward,$inward); 96 unless($matched) { 97 ($easting,$northing,$matched,$pc) = 98 execute($outer1_matcher,$outward,substr($inward,0,1)); 99 } 100 unless($matched) { 101 ($easting,$northing,$matched,$pc) = 102 execute($outer_matcher,$outward); 103 } 104 unless($matched) { 105 my ($mpart) = ($outward =~ /^([A-Z]+)\d/); 106 my $mlen = length($mpart); 107 108 ($easting,$northing,$matched,$pc) = 109 execute($area_matcher,$mpart,$mlen,$mpart,$mlen); 110 131 # Find what the user was after 132 if($request{type} eq "area") { 133 @results = execute_lt($pc_area_matcher, $request{easting}, $request{northing}, $limit_results); 134 } 135 elsif($request{type} eq "postcode") { 136 @results = execute_lt($postcode_matcher, $request{easting}, $request{northing}, $limit_results); 137 } 138 else { 139 my ($easting,$northing,$matched,$pc); 140 my ($outward,$inward) = ($request{outward},$request{inward}); 141 142 # Work out until we find a match 143 ($easting,$northing,$matched,$pc) = execute_ptl($full_matcher,$outward,$inward); 111 144 unless($matched) { 112 print_err "Postcode area '$mpart' not found, postcode probably invalid"; 113 next REQUEST; 114 } 115 } 145 ($easting,$northing,$matched,$pc) = 146 execute_ptl($outer1_matcher,$outward,substr($inward,0,1)); 147 } 148 unless($matched) { 149 ($easting,$northing,$matched,$pc) = 150 execute_ptl($outer_matcher,$outward); 151 } 152 unless($matched) { 153 my ($mpart) = ($outward =~ /^([A-Z]+)\d/); 154 my $mlen = length($mpart); 155 156 ($easting,$northing,$matched,$pc) = 157 execute_ptl($area_matcher,$mpart,$mlen,$mpart,$mlen); 158 159 unless($matched) { 160 print_err "Postcode area '$mpart' not found, postcode probably invalid"; 161 next REQUEST; 162 } 163 } 164 165 # Save the results 166 my %res; 167 $res{easting} = $easting; 168 $res{northing} = $northing; 169 $res{matched} = $matched; 170 $res{postcode} = $pc; 171 push @results, \%res; 172 } 173 174 175 # Format the easting and northing, if we have them 176 foreach my $res (@results) { 177 if($res->{easting}) { 178 $res->{ieasting} = int($res->{easting}); 179 } 180 if($res->{northing}) { 181 $res->{inorthing} = int($res->{northing}); 182 } 183 } 184 116 185 117 186 # Render … … 121 190 print "<geocoder>\n"; 122 191 print " <request>\n"; 123 print " <postcode>$postcode</postcode>\n"; 124 print " <outward>$outward</outward>\n"; 125 print " <inward>$inward</inward>\n"; 192 if($request{postcode}) { 193 print " <postcode>$request{postcode}</postcode>\n"; 194 print " <outward>$request{outward}</outward>\n"; 195 print " <inward>$request{inward}</inward>\n"; 196 } else { 197 print " <easting>$request{easting}</easting>\n"; 198 print " <northing>$request{northing}</northing>\n"; 199 } 126 200 print " </request>\n\n"; 127 print " <easting>".int($easting)."</easting>\n"; 128 print " <northing>".int($northing)."</northing>\n"; 129 print " <postcode>$pc</postcode>\n"; 201 202 foreach my $res (@results) { 203 if(scalar @results > 1) { 204 print " <result>\n"; 205 } 206 print " <easting>".$res->{ieasting}."</easting>\n"; 207 print " <northing>".$res->{inorthing}."</northing>\n"; 208 print " <postcode>$res->{postcode}</postcode>\n"; 209 if(scalar @results > 1) { 210 print " </result>\n"; 211 } 212 } 213 130 214 print "</geocoder>\n"; 131 215 } elsif ($output eq "js") { 132 216 print header("text/javascript"); 133 my ($e, $n) = (int($easting), int($northing)); 134 if(defined $cgi->param("callback")) { 135 print $cgi->param("callback") . "("; 136 } 137 print "{ pc: \"$pc\", e: $e, n: $n }"; 138 if(defined $cgi->param("callback")) { 139 print ");"; 140 } 141 print "\n"; 142 217 218 if(defined $cgi->param("callback")) { 219 print $cgi->param("callback") . "("; 220 } 221 # TODO: 222 # make me play nicely if there are several results 223 # (need to do some array magic probably) 224 foreach my $res (@results) { 225 print "{ pc: \"$res->{postcode}\", e: $res->{ieasting}, n: $res->{inorthing} }"; 226 } 227 if(defined $cgi->param("callback")) { 228 print ");"; 229 } 230 print "\n"; 143 231 } else { 144 232 print header("text/plain"); 145 233 print "# Easting,Northing,Matched Postcode\n"; 146 print int($easting).",".int($northing).",'$pc'\n"; 234 235 foreach my $res (@results) { 236 print $res->{ieasting}.",".$res->{inorthing}.",'".$res->{postcode}."'\n"; 237 } 147 238 } 148 239 } … … 151 242 $dbh->disconnect; 152 243 153 # Run a matcher query154 sub execute {244 # Run a postcode to location matcher 245 sub execute_ptl { 155 246 my $matcher = shift; 156 247 my @args = @_; … … 165 256 return ($easting,$northing,$matched,$pc); 166 257 } 258 259 # Run a location to postcode/area matcher 260 sub execute_lt { 261 my $matcher = shift; 262 my @args = @_; 263 264 my @results; 265 266 $matcher->execute(@args); 267 while( my @row = $matcher->fetchrow_array ) { 268 my %res = ( 269 outward => $row[0], 270 inward => $row[1], 271 easting => $row[2], 272 northing => $row[3] 273 ); 274 275 if($res{inward}) { 276 $res{postcode} = $res{outward}." ".$res{inward}; 277 } else { 278 $res{postcode} = $res{outward}; 279 } 280 281 push @results, \%res; 282 } 283 284 return @results; 285 } 286 167 287 168 288 # Build our various matcher prepared statements … … 217 337 my $dbh = shift; 218 338 219 my $sql = "SELECT outward, avg_e AS easting, avg_n AS northing ".339 my $sql = "SELECT outward, '' AS inward, avg_e AS easting, avg_n AS northing ". 220 340 "FROM ( ". 221 341 " SELECT outward, ".
Note: See TracChangeset
for help on using the changeset viewer.