File Coverage

blib/lib/Geo/Converter/WKT2KML.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Geo::Converter::WKT2KML;
2              
3 5     5   398253 use warnings;
  5         12  
  5         142  
4 5     5   26 use strict;
  5         8  
  5         138  
5 5     5   24 use Carp;
  5         14  
  5         393  
6 5     5   2301 use XML::Simple;
  0            
  0            
7             $XML::Simple::PREFERRED_PARSER = 'XML::Parser';
8              
9             use version; our $VERSION = qv('0.0.3');
10             use base 'Exporter';
11              
12             our @EXPORT = qw(
13             wkt2kml
14             kml2wkt
15             );
16              
17             my $coord = qr{[\+\-]?\d+(?:\.\d+)?};
18             my $formatter;
19             $formatter = {
20             'point' => sub {
21             '' . coordformatter( $_[0] ) . ''
22             },
23             'multipoint' => sub {
24             $formatter->{geometrycollection}->([
25             map { $formatter->{point}->([$_]) } @{$_[0]}
26             ]);
27             },
28             'linestring' => sub {
29             '' . coordformatter( $_[0] ) . ''
30             },
31             'multilinestring' => sub {
32             $formatter->{geometrycollection}->([
33             map { $formatter->{linestring}->($_) } @{$_[0]}
34             ]);
35             },
36             'polygon' => sub {
37             my @lnr;
38             push @lnr, $formatter->{LinearRing}->([shift(@{$_[0]})],'outerBoundaryIs');
39             push @lnr, $formatter->{LinearRing}->($_[0],'innerBoundaryIs') if ( @{ $_[0] } );
40             "\n" . join( "\n", @lnr ) . "\n";
41             },
42             'LinearRing' => sub {
43             my $bound = $_[1];
44             join ( "\n", map { "<$bound>" . coordformatter( $_ ) . "" } @{$_[0]} );
45             },
46             'multipolygon' => sub {
47             $formatter->{geometrycollection}->([
48             map { $formatter->{polygon}->($_) } @{$_[0]}
49             ]);
50             },
51             'geometrycollection' => sub {
52             "\n" . join( "\n", @{$_[0]} ) . "\n"
53             },
54             };
55              
56             sub coordformatter {
57             my @coords = @{$_[0]};
58             join( "\n", map { my $s = $_; $s =~ s/\s+/,/g; $s } @coords );
59             }
60              
61             sub wkt2kmlparser {
62             return wkt2kmlformatter($_[1]) unless $_[0];
63             $_[0] =~ s{\A # start of the string
64             \s* # spaces
65             ( [\(\)] # paren
66             | [a-zA-Z]+ # command
67             | (?:$coord\s+)+$coord # coordinate
68             | , # delimiter
69             )
70             }{}x;
71             return wkt2kmlformatter($_[1]) if $1 eq ')';
72             my $token =
73             $1 eq '(' ? wkt2kmlparser( $_[0], [] ) :
74             $1 ne ',' ? lc($1)
75             : undef;
76             push @{ $_[1] }, $token if ( defined( $token ) );
77             goto &wkt2kmlparser;
78             }
79              
80             sub wkt2kmlformatter {
81             return $_[0] if ( !ref($_[0]) || $_[0]->[0] !~ /^[a-z]+$/ );
82              
83             my @args = @{$_[0]};
84             my @reslt;
85              
86             while ( my $command = shift(@args) ) {
87             if ( my $format = $formatter->{$command} ) {
88             push ( @reslt, $format->( shift @args ) );
89             } else {
90             croak "WKT $command cannot be interpreted";
91             }
92             }
93              
94             return @reslt > 1 ? \@reslt : $reslt[0];
95             }
96              
97             sub wkt2kml { wkt2kmlparser( $_[0], []) }
98              
99             my $builder;
100             $builder = {
101             'Point' => sub {
102             my $buf = 'POINT(' . join( ',', map { coordbuilder($_->{coordinates}) } @{$_[0]} ) . ')';
103             $buf = 'MULTI' . $buf if ( @{$_[0]} > 1 );
104             $buf;
105             },
106             'LineString' => sub {
107             my $buf = '(' . join( '),(', map { coordbuilder($_->{coordinates}) } @{$_[0]} ) . ')';
108             $buf = @{$_[0]} > 1 ? "MULTILINESTRING($buf)" : "LINESTRING$buf";
109             $buf;
110             },
111             'Polygon' => sub {
112             my $buf = '(' . join( '),(', map { $builder->{linearring}->($_) } @{$_[0]} ) . ')';
113             $buf = @{$_[0]} > 1 ? "MULTIPOLYGON($buf)" : "POLYGON$buf";
114             $buf;
115             },
116             'linearring' => sub {
117             my @lnr;
118             push( @lnr, $_[0]->{outerBoundaryIs}->{LinearRing}->{coordinates} );
119             push( @lnr, map { $_->{LinearRing}->{coordinates} } ( ref($_[0]->{innerBoundaryIs}) eq 'ARRAY' ? @{$_[0]->{innerBoundaryIs}} : ($_[0]->{innerBoundaryIs}) ) )
120             if ( defined($_[0]->{innerBoundaryIs}) );
121             '(' . join( '),(', map { coordbuilder($_) } @lnr ) . ')';
122             },
123             'MultiGeometry' => sub {
124             my @key = grep { $builder->{$_} } keys %{$_[0]->[0]};
125             my $buf = join( ',', map { kml2wktbuilder( $_, $_[0]->[0]->{$_} ) } @key );
126             $buf = "GEOMETRYCOLLECTION($buf)" if ( @key > 1 );
127             $buf;
128             },
129             };
130              
131             sub coordbuilder {
132             my $coords = $_[0];
133             $coords =~ s/^[\s\n]*(.+)[\s\n]*$/$1/m;
134             my @coords = split( /[\s\n]+/, $coords );
135             join( ",", map { my $s = $_; $s =~ s/,/ /g; $s } @coords );
136             }
137              
138             sub kml2wktbuilder {
139             my $key = shift;
140             my $arg = shift;
141              
142             if ( my $build = $builder->{$key} ) {
143             my @reslt = $build->( ref($arg) eq 'ARRAY' ? $arg : [$arg]);
144             return @reslt > 1 ? \@reslt : $reslt[0];
145             } else {
146             croak "KML $key element cannot be interpreted";
147             }
148             }
149              
150             sub kml2wkt {
151             my $xml = XMLin($_[0],KeepRoot => 1);
152             my ($key) = keys %{$xml};
153             kml2wktbuilder( $key, $xml->{$key} );
154             }
155              
156             1; # Magic true value required at end of module
157             __END__