| Geo-GeoNames-Record documentation | Contained in the Geo-GeoNames-Record distribution. |
Geo::GeoNames::Record - Perl module for handling GeoNames.org records
Provides a Perl extension for handling GeoNames.org records.
Xiangrui Meng <mengxr@stanford.edu>
GoeNames: http://www.geonames.org/
This package is part of the metadata generation and remediation suite: http://cads.stanford.edu/
Copyright (C) 2009 by Xiangrui Meng
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.
Each Geo::GeoNames::Record instance has the following fields defined in http://download.geonames.org/export/dump/readme.txt:
geonameid : integer id of record in geonames database
name : name of geographical point (utf8) varchar(200)
asciiname : name of geographical point in plain ascii characters, varchar(200)
alternatenames : alternatenames, comma separated varchar(4000) (varchar(5000) for SQL Server)
latitude : latitude in decimal degrees (wgs84)
longitude : longitude in decimal degrees (wgs84)
feature_class : see http://www.geonames.org/export/codes.html, char(1)
feature_code : see http://www.geonames.org/export/codes.html, varchar(10)
country_code : ISO-3166 2-letter country code, 2 characters
cc2 : alternate country codes, comma separated, ISO-3166 2-letter country code, 60 characters
admin1_code : fipscode (subject to change to iso code), isocode for the us and ch, see file admin1Codes.txt for display names of this code; varchar(20)
admin2_code : code for the second administrative division, a county in the US, see file admin2Codes.txt; varchar(80)
admin3_code : code for third level administrative division, varchar(20)
admin4_code : code for fourth level administrative division, varchar(20)
population : bigint (4 byte int)
elevation : in meters, integer
gtopo30 : average elevation of 30'x30' (ca 900mx900m) area in meters, integer
timezone : the timezone id (see file timeZone.txt)
modification_date : date of last modification in yyyy-MM-dd format
For each member variable, we defined a member function to save the curly brackets from your code. For example, you can get the value of $rec->{geonameid} by
$rec->geonameid;
or set its value by
$rec->geonameid = 123456;
We defined several aliases as followed:
id : geonameid;
coordinates : (latitude,longitude);
Constructor for Geo::GeoNames::Record.
my $rec = Geo::GeoNames::Record->new();
It returns an empty Geo::GeoNames::Record object.
my $rec = Geo::GeoNames::Record->new( $str_record );
You may also pass a GeoNames record string. It returns the corresponding Geo::GeoNames::Record object or undef if the input is incorrect.
$rec->parse( $line );
Parses a record line from a GeoNames.org data file and updates the current object.
Returns all unique names.
Returns true if the record has a name matching the $name argument.
Return the country of the record as a Geo::GeoNames::Record object.
Return the admin1 of the record as a Geo::GeoNames::Record object.
Return the admin2 of the record as a Geo::GeoNames::Record object.
Convert the record to a GeoNames.org record line.
Compare records based on their geonameids.
Return true if the record is a country.
Return true if the record is a primary administrative division.
Return true if the record is a second-order administrative division.
| Geo-GeoNames-Record documentation | Contained in the Geo-GeoNames-Record distribution. |
package Geo::GeoNames::Record;
use 5.008007; use strict; use warnings; require Exporter; our @ISA = qw(Exporter); our %EXPORT_TAGS = ( 'all' => [ qw() ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( ); our $VERSION = '0.11'; use Carp (); use Data::Dumper (); use File::Basename (); use Storable (); ## overloadings ## use overload q("") => \&as_string, q(eq) => \&op_eq, q(==) => \&op_eq, ; ## public static variables ## our @fields = qw( geonameid name asciiname alternatenames latitude longitude feature_class feature_code country_code cc2 admin1_code admin2_code admin3_code admin4_code population elevation gtopo30 timezone modification_date ); our $n_fields = @fields;
## public variables and corresponding member functions ## my @_PUBLIC_VARIABLES = @fields; foreach (@_PUBLIC_VARIABLES) { eval "sub $_ : lvalue { shift->{$_}; }"; }
my %_PUBLIC_VARIABLE_ALIASES = ( id => 'geonameid' ); foreach (keys %_PUBLIC_VARIABLE_ALIASES) { eval "sub $_ : lvalue { shift->{$_PUBLIC_VARIABLE_ALIASES{$_}}; }"; } sub coordinates : lvalue { my $self = shift; ($self->{latitude}, $self->{longitude}); } ## private static variables ## my $_admins_loaded; my $_admin_code_to_record;
sub new { my $class = shift; my $self = bless {}, $class; @{$self}{@fields} = (); if ( @_ ) { $self->parse( @_ ); } return $self; }
sub parse { my ( $self, $str ) = @_; chomp($str); my @data = split /\t/, $str; if ( @data == $n_fields ) { for ( my $i = 0; $i < $n_fields; $i++ ) { $self->{$fields[$i]} = $data[$i]; } } else { Carp::croak "Wrong number of GeoNames fields"; } return $self; }
sub names { my $self = shift; my %saw; @saw{ ( $self->{name}, $self->{asciiname}, split(/,/, $self->{alternatenames}) ) } = (); return keys %saw; }
sub has_name { my ($self, $name) = @_; return ( grep { $_ eq $name; } $self->names() ) ? 1 : 0; }
sub country { _load_admins() unless $_admins_loaded; my $self = shift; if ( $self->{country_code} && exists( $_admin_code_to_record->{$self->{country_code}} ) ) { return $_admin_code_to_record->{$self->{country_code}}; } return; }
sub admin1 { _load_admins() unless $_admins_loaded; my $self = shift; if ( $self->{admin1_code} ) { my $admin1_key = $self->{country_code} . "." . $self->{admin1_code}; if ( exists( $_admin_code_to_record->{$admin1_key} ) ) { return $_admin_code_to_record->{$admin1_key}; } } return; }
sub admin2 { _load_admins() unless $_admins_loaded; my $self = shift; if ( $self->{admin2_code} ) { my $admin2_key = $self->{country_code} . "." . $self->{admin1_code} . "." . $self->{admin2_code}; if ( exists( $_admin_code_to_record->{$admin2_key} ) ) { return $_admin_code_to_record->{$admin2_key}; } } return; }
sub as_string { my $self = shift; return join( "\t", @{$self}{@fields} ); }
sub op_eq { return ($_[0]->id eq $_[1]->id); }
sub is_country { my $self = shift; return ( $self->{feature_class} eq 'A' ) && ( $self->{feature_code} =~ /^P/ ); }
sub is_admin1 { my $self = shift; return ( $self->{feature_class} eq 'A' ) && ( $self->{feature_code} eq 'ADM1' ); }
sub is_admin2 { my $self = shift; return ( $self->{feature_class} eq 'A' ) && ( $self->{feature_code} eq 'ADM2' ); } ## private functions ## # load data files for decoding country_code, admin1_code and admin2_code sub _load_admins { use File::HomeDir; use File::Spec; my $admins_filename = File::Spec->catfile( File::HomeDir->my_home(), ".Geo-GeoNames-Record", "admin_code_to_record.hash" ); if( -e $admins_filename ) { $_admin_code_to_record = Storable::retrieve( $admins_filename ); $_admins_loaded = 1; } else { Carp::croak( "$admins_filename doesn't exist. Please run gn_update_admins first." ); } }
1; __END__