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

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

   
Visit the ZANavi Wiki