/[zanavi_public1]/navit/navit/script/osm/Geo/OSM/OsmChangeReaderV3.pm
ZANavi

Contents of /navit/navit/script/osm/Geo/OSM/OsmChangeReaderV3.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations) (download)
Fri Oct 28 21:19:04 2011 UTC (12 years, 5 months ago) by zoff99
File size: 8729 byte(s)
import files
1 ##################################################################
2 ## OsmChangeReader.pm - Library for reading OSM change files ##
3 ## By Martijn van Oosterhout <kleptog@svana.org> ##
4 ## ##
5 ## Package that reads both osmChange and JOSM file format change##
6 ## files. The user creates the parse with a callback and the ##
7 ## loader will call the callback for each detected change. Note ##
8 ## that for JOSM file entires that are not changes are ignored. ##
9 ## ##
10 ## Licence: LGPL ##
11 ##################################################################
12 package Geo::OSM::OsmChangeReader;
13
14 use strict;
15 use warnings;
16
17 use Utils::File;
18 use Utils::Math;
19 use Utils::Debug;
20 use XML::Parser;
21 use Carp;
22
23 use Geo::OSM::EntitiesV3;
24
25 use constant STATE_INIT => 1;
26 use constant STATE_EXPECT_COMMAND => 2;
27 use constant STATE_EXPECT_ENTITY => 3;
28 use constant STATE_EXPECT_BODY => 4;
29
30 use constant FILETYPE_UNKNOWN => 0;
31 use constant FILETYPE_OSMCHANGE => 1;
32 use constant FILETYPE_OSM => 2;
33
34 sub new
35 {
36 my $obj = bless{}, shift;
37 my $proc = shift;
38 my $prog = shift;
39 if( ref $proc ne "CODE" )
40 { die "new Geo::OSM::OsmChangeReader requires a sub as argument\n" }
41 $obj->{oldproc} = $proc;
42 if( defined $prog )
43 { $obj->{progress} = $prog }
44 return $obj;
45 }
46
47 # With this initialiser, your process will get called with instantiated objects rather than useless details
48 sub init
49 {
50 my $obj = bless{}, shift;
51 my $proc = shift;
52 my $prog = shift;
53 if( ref $proc ne "CODE" )
54 { die "init Geo::OSM::OsmChangeReader requires a sub as argument\n" }
55 $obj->{newproc} = $proc;
56 if( defined $prog )
57 { $obj->{progress} = $prog }
58 return $obj;
59 }
60
61 sub _process
62 {
63 my($self, $command, $entity, $attr, $tags, $segs) = @_;
64
65 if( defined $self->{oldproc} )
66 {
67 return $self->{oldproc}->($command, $entity, $attr, $tags, $segs);
68 }
69
70 my $ent;
71 if( $entity eq "node" )
72 {
73 $ent = new Geo::OSM::Node( $attr, $tags );
74 }
75 if( $entity eq "segment" )
76 {
77 $ent = new Geo::OSM::Segment( $attr, $tags );
78 }
79 if( $entity eq "way" )
80 {
81 $ent = new Geo::OSM::Way( $attr, $tags, $segs );
82 }
83 croak "Unknown entity '$entity'" if not defined $ent;
84
85 return $self->{newproc}->($command, $ent );
86 }
87
88 sub load{
89 my ($self, $file_name) = @_;
90
91 $self->{filetype} = FILETYPE_UNKNOWN;
92 $self->{state} = STATE_INIT;
93
94 my $start_time = time();
95 my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
96 my $fh = data_open($file_name);
97 die "Cannot open OSM File $file_name\n" unless $fh;
98 $self->{input_length} = -s $fh;
99 $self->{count}=0;
100 eval {
101 $P->parse($fh);
102 };
103 print "\n" if $DEBUG || $VERBOSE;
104 if ( $VERBOSE) {
105 printf "Read and parsed $file_name in %.0f sec\n",time()-$start_time;
106 }
107 if ( $@ ) {
108 warn "$@Error while parsing\n $file_name\n";
109 return;
110 }
111 if (not $P) {
112 warn "WARNING: Could not parse osm data\n";
113 return;
114 }
115
116 }
117
118 sub parse($)
119 {
120 my ($self, $string) = @_;
121
122 $self->{state} = STATE_INIT;
123
124 my $start_time = time();
125 my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
126 $self->{input_length} = length($string);
127 $self->{count}=0;
128 eval {
129 $P->parse($string);
130 };
131 print "\n" if $DEBUG || $VERBOSE;
132 if ( $VERBOSE) {
133 printf "Read and parsed string in %.0f sec\n",time()-$start_time;
134 }
135 if ( $@ ) {
136 warn "$@Error while parsing\n [$string]\n";
137 return;
138 }
139 if (not $P) {
140 warn "WARNING: Could not parse osm data\n";
141 return;
142 }
143 }
144
145 # Function is called whenever an XML tag is started
146 sub DoStart
147 {
148 #print @_,"\n";
149 my ($self, $Expat, $Name, %Attr) = @_;
150
151 if( $self->{filetype} == FILETYPE_UNKNOWN )
152 {
153 if( $self->{state} == STATE_INIT )
154 {
155 if($Name eq "osmChange"){
156 $self->{state} = STATE_EXPECT_COMMAND;
157 $self->{filetype} = FILETYPE_OSMCHANGE;
158
159 if( $Attr{version} ne "0.3" and $Attr{version} ne "0.4" )
160 { die "OsmChangeReaderV3 can only read 0.3 and 0.4 files, found '$Attr{version}'\n" }
161 } elsif($Name eq "osm"){
162 $self->{state} = STATE_EXPECT_ENTITY;
163 $self->{filetype} = FILETYPE_OSM;
164
165 if( $Attr{version} ne "0.3" and $Attr{version} ne "0.4" )
166 { die "OsmChangeReaderV3 can only read 0.3 and 0.4 files, found '$Attr{version}'\n" }
167 } else {
168 die "Expected 'osmChange' tag, got '$Name'\n";
169 }
170 }
171 }
172 elsif( $self->{state} == STATE_EXPECT_COMMAND )
173 {
174 if($Name eq 'create' or $Name eq 'modify' or $Name eq 'delete'){
175 $self->{command} = $Name;
176 $self->{state} = STATE_EXPECT_ENTITY;
177 } else {
178 die "Expected command\n";
179 }
180 }
181 elsif( $self->{state} == STATE_EXPECT_ENTITY )
182 {
183 # Pick up the origin attribute from the bound tag
184 if( $Name eq "bound" )
185 {
186 if( exists $Attr{origin} )
187 {
188 $self->{origin} = $Attr{origin};
189 }
190 return;
191 }
192 if($Name eq "node" or $Name eq "segment" or $Name eq "way"){
193 $self->{entity} = $Name;
194 $self->{attr} = {%Attr};
195 $self->{tags} = [];
196 $self->{segs} = ($Name eq "way") ? [] : undef;
197 $self->{state} = STATE_EXPECT_BODY;
198 } else {
199 die "Expected entity\n";
200 }
201 }
202 elsif( $self->{state} == STATE_EXPECT_BODY )
203 {
204 if($Name eq "tag"){
205 push @{$self->{tags}}, $Attr{"k"}, $Attr{"v"};
206 }
207 if($Name eq "seg"){
208 push @{$self->{segs}}, $Attr{"id"};
209 }
210 }
211 }
212
213 # Function is called whenever an XML tag is ended
214 sub DoEnd
215 {
216 my ($self, $Expat, $Name) = @_;
217 if( $self->{state} == STATE_EXPECT_BODY )
218 {
219 if( $Name eq $self->{entity} )
220 {
221 if( $self->{filetype} == FILETYPE_OSMCHANGE )
222 {
223 $self->_process( $self->{command}, $self->{entity}, $self->{attr}, $self->{tags}, $self->{segs} );
224 }
225 else # FILETYPE_OSM
226 {
227 # Only entities with a modify tag are interesting, or if they have a negative ID (that's create)
228 if( exists $self->{attr}->{action} )
229 {
230 $self->_process( $self->{attr}->{action}, $self->{entity}, $self->{attr}, $self->{tags}, $self->{segs} );
231 }
232 elsif( $self->{attr}{id} < 0 )
233 {
234 $self->_process( "create", $self->{entity}, $self->{attr}, $self->{tags}, $self->{segs} );
235 }
236 }
237 $self->{count}++;
238 if( $self->{progress} and ($self->{count}%11) == 1)
239 {
240 $self->{progress}->($self->{count}, $Expat->current_byte()/$self->{input_length} );
241 }
242 $self->{state} = STATE_EXPECT_ENTITY;
243 }
244 return;
245 }
246 elsif( $self->{state} == STATE_EXPECT_ENTITY )
247 {
248 return if $Name eq "bound";
249 if( $self->{filetype} == FILETYPE_OSMCHANGE )
250 {
251 if( $Name eq $self->{command} )
252 {
253 $self->{state} = STATE_EXPECT_COMMAND;
254 }else {die}
255 }
256 else # FILETYPE_OSM
257 {
258 if( $Name eq "osm" )
259 {
260 $self->{state} = STATE_INIT;
261 } else {die}
262 }
263 return;
264 }
265 elsif( $self->{state} == STATE_EXPECT_COMMAND )
266 {
267 if( $Name eq "osmChange" )
268 {
269 $self->{state} = STATE_INIT;
270 }else {die}
271 return;
272 }
273 }
274
275 1;
276
277 __END__
278
279 =head1 NAME
280
281 OsmChangeReaderV3 - Module for reading OpenStreetMap V3 Change XML data files
282
283 =head1 SYNOPSIS
284
285 my $OSM = new Geo::OSM::OsmChangeReader(\&process);
286 $OSM->load("Data/changes.osc");
287
288 sub process
289 {
290 my($OSM, $command, $entity, $attr, $tags, $segs) = @_;
291 print "Doing a $command on a $entity $attr->{id}\n";
292 while( my($k,$v) = splice @{$tags}, 0, 2 )
293 { print " $k: $v\n" }
294 if( defined $segs )
295 { print " Segs: ", join(", ",@$segs),"\n"; }
296 }
297
298 =head1 AUTHOR
299
300 Martijn van Oosterhout <kleptog@svana.org>
301 based on OsmXML.pm written by:
302 Oliver White (oliver.white@blibbleblobble.co.uk)
303
304 =head1 COPYRIGHT
305
306 Copyright 2007, Martijn van Oosterhout
307 Copyright 2006, Oliver White
308
309 This program is free software; you can redistribute it and/or
310 modify it under the terms of the GNU General Public License
311 as published by the Free Software Foundation; either version 2
312 of the License, or (at your option) any later version.
313
314 This program is distributed in the hope that it will be useful,
315 but WITHOUT ANY WARRANTY; without even the implied warranty of
316 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
317 GNU General Public License for more details.
318
319 You should have received a copy of the GNU General Public License
320 along with this program; if not, write to the Free Software
321 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
322
323 =cut

   
Visit the ZANavi Wiki