source: subversion/applications/utils/export/osm2pgsql/parse-xml2.c @ 26711

Last change on this file since 26711 was 26588, checked in by apmon, 8 years ago

[osm2pgsql] Report some more timing information to see where osm2pgsql spends its time

File size: 14.0 KB
Line 
1/*
2#-----------------------------------------------------------------------------
3# osm2pgsql - converts planet.osm file into PostgreSQL
4# compatible output suitable to be rendered by mapnik
5#-----------------------------------------------------------------------------
6# Original Python implementation by Artem Pavlenko
7# Re-implementation by Jon Burgess, Copyright 2006
8#
9# This program is free software; you can redistribute it and/or
10# modify it under the terms of the GNU General Public License
11# as published by the Free Software Foundation; either version 2
12# of the License, or (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22#-----------------------------------------------------------------------------
23*/
24
25#define _GNU_SOURCE
26
27#include <unistd.h>
28#include <stdlib.h>
29#include <string.h>
30#include <assert.h>
31#include <time.h>
32
33#include <libxml/xmlstring.h>
34#include <libxml/xmlreader.h>
35
36#include "osmtypes.h"
37#include "sanitizer.h"
38#include "reprojection.h"
39#include "input.h"
40#include "output.h"
41
42#include "parse-xml2.h"
43
44
45
46/* Parses the action="foo" tags in JOSM change files. Obvisouly not useful from osmChange files */
47static actions_t ParseAction( xmlTextReaderPtr reader, struct osmdata_t *osmdata )
48{
49    if( osmdata->filetype == FILETYPE_OSMCHANGE || osmdata->filetype == FILETYPE_PLANETDIFF )
50        return osmdata->action;
51    actions_t new_action = ACTION_NONE;
52    xmlChar *action = xmlTextReaderGetAttribute( reader, BAD_CAST "action" );
53    if( action == NULL )
54        new_action = ACTION_CREATE;
55    else if( strcmp((char *)action, "modify") == 0 )
56        new_action = ACTION_MODIFY;
57    else if( strcmp((char *)action, "delete") == 0 )
58        new_action = ACTION_DELETE;
59    else
60    {
61        fprintf( stderr, "Unknown value for action: %s\n", (char*)action );
62        exit_nicely();
63    }
64    return new_action;
65}
66
67static void StartElement(xmlTextReaderPtr reader, const xmlChar *name, struct osmdata_t *osmdata)
68{
69    xmlChar *xid, *xlat, *xlon, *xk, *xv, *xrole, *xtype;
70    char *k;
71
72    if (osmdata->filetype == FILETYPE_NONE)
73    {
74        if (xmlStrEqual(name, BAD_CAST "osm"))
75        {
76            osmdata->filetype = FILETYPE_OSM;
77            osmdata->action = ACTION_CREATE;
78        }
79        else if (xmlStrEqual(name, BAD_CAST "osmChange"))
80        {
81            osmdata->filetype = FILETYPE_OSMCHANGE;
82            osmdata->action = ACTION_NONE;
83        }
84        else if (xmlStrEqual(name, BAD_CAST "planetdiff"))
85        {
86            osmdata->filetype = FILETYPE_PLANETDIFF;
87            osmdata->action = ACTION_NONE;
88        }
89        else
90        {
91            fprintf( stderr, "Unknown XML document type: %s\n", name );
92            exit_nicely();
93        }
94        return;
95    }
96   
97    if (xmlStrEqual(name, BAD_CAST "node")) {
98        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
99        xlon = xmlTextReaderGetAttribute(reader, BAD_CAST "lon");
100        xlat = xmlTextReaderGetAttribute(reader, BAD_CAST "lat");
101        assert(xid); assert(xlon); assert(xlat);
102
103        osmdata->osm_id   = strtoosmid((char *)xid, NULL, 10);
104        osmdata->node_lon = strtod((char *)xlon, NULL);
105        osmdata->node_lat = strtod((char *)xlat, NULL);
106        osmdata->action   = ParseAction( reader , osmdata);
107
108        if (osmdata->osm_id > osmdata->max_node)
109            osmdata->max_node = osmdata->osm_id;
110
111        if (osmdata->count_node == 0) {
112            time(&osmdata->start_node);
113        }
114        osmdata->count_node++;
115        if (osmdata->count_node%10000 == 0)
116            printStatus(osmdata);
117
118        xmlFree(xid);
119        xmlFree(xlon);
120        xmlFree(xlat);
121    } else if (xmlStrEqual(name, BAD_CAST "tag")) {
122        xk = xmlTextReaderGetAttribute(reader, BAD_CAST "k");
123        assert(xk);
124
125        /* 'created_by' and 'source' are common and not interesting to mapnik renderer */
126        if (strcmp((char *)xk, "created_by") && strcmp((char *)xk, "source")) {
127            char *p;
128            xv = xmlTextReaderGetAttribute(reader, BAD_CAST "v");
129            assert(xv);
130            k  = (char *)xmlStrdup(xk);
131            while ((p = strchr(k, ' ')))
132                *p = '_';
133
134            addItem(&(osmdata->tags), k, (char *)xv, 0);
135            xmlFree(k);
136            xmlFree(xv);
137        }
138        xmlFree(xk);
139    } else if (xmlStrEqual(name, BAD_CAST "way")) {
140
141        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
142        assert(xid);
143        osmdata->osm_id   = strtoosmid((char *)xid, NULL, 10);
144        osmdata->action = ParseAction( reader, osmdata );
145
146        if (osmdata->osm_id > osmdata->max_way)
147            osmdata->max_way = osmdata->osm_id;
148
149        if (osmdata->count_way == 0) {
150            time(&osmdata->start_way);
151        }
152        osmdata->count_way++;
153        if (osmdata->count_way%1000 == 0)
154        printStatus(osmdata);
155
156        osmdata->nd_count = 0;
157        xmlFree(xid);
158
159    } else if (xmlStrEqual(name, BAD_CAST "nd")) {
160        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "ref");
161        assert(xid);
162
163        osmdata->nds[osmdata->nd_count++] = strtoosmid( (char *)xid, NULL, 10 );
164
165        if( osmdata->nd_count >= osmdata->nd_max )
166          realloc_nodes(osmdata);
167        xmlFree(xid);
168    } else if (xmlStrEqual(name, BAD_CAST "relation")) {
169        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
170        assert(xid);
171        osmdata->osm_id   = strtoosmid((char *)xid, NULL, 10);
172        osmdata->action = ParseAction( reader, osmdata );
173
174        if (osmdata->osm_id > osmdata->max_rel)
175            osmdata->max_rel = osmdata->osm_id;
176
177        if (osmdata->count_rel == 0) {
178            time(&osmdata->start_rel);
179        }
180        osmdata->count_rel++;
181        if (osmdata->count_rel%10 == 0)
182            printStatus(osmdata);
183
184        osmdata->member_count = 0;
185        xmlFree(xid);
186    } else if (xmlStrEqual(name, BAD_CAST "member")) {
187        xrole = xmlTextReaderGetAttribute(reader, BAD_CAST "role");
188        assert(xrole);
189
190        xtype = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
191        assert(xtype);
192
193        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "ref");
194        assert(xid);
195
196        osmdata->members[osmdata->member_count].id   = strtoosmid( (char *)xid, NULL, 0 );
197        osmdata->members[osmdata->member_count].role = strdup( (char *)xrole );
198       
199        /* Currently we are only interested in 'way' members since these form polygons with holes */
200        if (xmlStrEqual(xtype, BAD_CAST "way"))
201            osmdata->members[osmdata->member_count].type = OSMTYPE_WAY;
202        if (xmlStrEqual(xtype, BAD_CAST "node"))
203            osmdata->members[osmdata->member_count].type = OSMTYPE_NODE;
204        if (xmlStrEqual(xtype, BAD_CAST "relation"))
205            osmdata->members[osmdata->member_count].type = OSMTYPE_RELATION;
206        osmdata->member_count++;
207
208        if( osmdata->member_count >= osmdata->member_max )
209          realloc_members(osmdata);
210        xmlFree(xid);
211        xmlFree(xrole);
212        xmlFree(xtype);
213    } else if (xmlStrEqual(name, BAD_CAST "add") ||
214               xmlStrEqual(name, BAD_CAST "create")) {
215        osmdata->action = ACTION_MODIFY; // Turns all creates into modifies, makes it resiliant against inconsistant snapshots.
216    } else if (xmlStrEqual(name, BAD_CAST "modify")) {
217        osmdata->action = ACTION_MODIFY;
218    } else if (xmlStrEqual(name, BAD_CAST "delete")) {
219        osmdata->action = ACTION_DELETE;
220    } else if (xmlStrEqual(name, BAD_CAST "bound")) {
221        /* ignore */
222    } else if (xmlStrEqual(name, BAD_CAST "bounds")) {
223        /* ignore */
224    } else if (xmlStrEqual(name, BAD_CAST "changeset")) {
225        /* ignore */
226    } else {
227        fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
228    }
229
230    // Collect extra attribute information and add as tags
231    if (osmdata->extra_attributes && (xmlStrEqual(name, BAD_CAST "node") ||
232                                      xmlStrEqual(name, BAD_CAST "way") ||
233                                      xmlStrEqual(name, BAD_CAST "relation")))
234    {
235        xmlChar *xtmp;
236
237        xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "user");
238        if (xtmp) {
239            addItem(&(osmdata->tags), "osm_user", (char *)xtmp, 0);
240            xmlFree(xtmp);
241        }
242
243        xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "uid");
244        if (xtmp) {
245            addItem(&(osmdata->tags), "osm_uid", (char *)xtmp, 0);
246            xmlFree(xtmp);
247        }
248
249        xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "version");
250        if (xtmp) {
251            addItem(&(osmdata->tags), "osm_version", (char *)xtmp, 0);
252            xmlFree(xtmp);
253        }
254
255        xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp");
256        if (xtmp) {
257            addItem(&(osmdata->tags), "osm_timestamp", (char *)xtmp, 0);
258            xmlFree(xtmp);
259        }
260    }
261}
262
263
264static void EndElement(const xmlChar *name, struct osmdata_t *osmdata)
265{
266    if (xmlStrEqual(name, BAD_CAST "node")) {
267      if (node_wanted(osmdata, osmdata->node_lat, osmdata->node_lon)) {
268          reproject(&(osmdata->node_lat), &(osmdata->node_lon));
269            if( osmdata->action == ACTION_CREATE )
270                osmdata->out->node_add(osmdata->osm_id, osmdata->node_lat, osmdata->node_lon, &(osmdata->tags));
271            else if( osmdata->action == ACTION_MODIFY )
272                osmdata->out->node_modify(osmdata->osm_id, osmdata->node_lat, osmdata->node_lon, &(osmdata->tags));
273            else if( osmdata->action == ACTION_DELETE )
274                osmdata->out->node_delete(osmdata->osm_id);
275            else
276            {
277                fprintf( stderr, "Don't know action for node %" PRIdOSMID "\n", osmdata->osm_id );
278                exit_nicely();
279            }
280        }
281        resetList(&(osmdata->tags));
282    } else if (xmlStrEqual(name, BAD_CAST "way")) {
283        if( osmdata->action == ACTION_CREATE )
284            osmdata->out->way_add(osmdata->osm_id, osmdata->nds, osmdata->nd_count, &(osmdata->tags) );
285        else if( osmdata->action == ACTION_MODIFY )
286            osmdata->out->way_modify(osmdata->osm_id, osmdata->nds, osmdata->nd_count, &(osmdata->tags) );
287        else if( osmdata->action == ACTION_DELETE )
288            osmdata->out->way_delete(osmdata->osm_id);
289        else
290        {
291            fprintf( stderr, "Don't know action for way %" PRIdOSMID "\n", osmdata->osm_id );
292            exit_nicely();
293        }
294        resetList(&(osmdata->tags));
295    } else if (xmlStrEqual(name, BAD_CAST "relation")) {
296        if( osmdata->action == ACTION_CREATE )
297            osmdata->out->relation_add(osmdata->osm_id, osmdata->members, osmdata->member_count, &(osmdata->tags));
298        else if( osmdata->action == ACTION_MODIFY )
299            osmdata->out->relation_modify(osmdata->osm_id, osmdata->members, osmdata->member_count, &(osmdata->tags));
300        else if( osmdata->action == ACTION_DELETE )
301            osmdata->out->relation_delete(osmdata->osm_id);
302        else
303        {
304            fprintf( stderr, "Don't know action for relation %" PRIdOSMID "\n", osmdata->osm_id );
305            exit_nicely();
306        }
307        resetList(&(osmdata->tags));
308        resetMembers(osmdata);
309    } else if (xmlStrEqual(name, BAD_CAST "tag")) {
310        /* ignore */
311    } else if (xmlStrEqual(name, BAD_CAST "nd")) {
312        /* ignore */
313    } else if (xmlStrEqual(name, BAD_CAST "member")) {
314        /* ignore */
315    } else if (xmlStrEqual(name, BAD_CAST "osm")) {
316        printStatus(osmdata);
317        osmdata->filetype = FILETYPE_NONE;
318    } else if (xmlStrEqual(name, BAD_CAST "osmChange")) {
319        printStatus(osmdata);
320        osmdata->filetype = FILETYPE_NONE;
321    } else if (xmlStrEqual(name, BAD_CAST "planetdiff")) {
322        printStatus(osmdata);
323        osmdata->filetype = FILETYPE_NONE;
324    } else if (xmlStrEqual(name, BAD_CAST "bound")) {
325        /* ignore */
326    } else if (xmlStrEqual(name, BAD_CAST "bounds")) {
327        /* ignore */
328    } else if (xmlStrEqual(name, BAD_CAST "changeset")) {
329        /* ignore */
330        resetList(&(osmdata->tags)); /* We may have accumulated some tags even if we ignored the changeset */
331    } else if (xmlStrEqual(name, BAD_CAST "add")) {
332        osmdata->action = ACTION_NONE;
333    } else if (xmlStrEqual(name, BAD_CAST "create")) {
334        osmdata->action = ACTION_NONE;
335    } else if (xmlStrEqual(name, BAD_CAST "modify")) {
336        osmdata->action = ACTION_NONE;
337    } else if (xmlStrEqual(name, BAD_CAST "delete")) {
338        osmdata->action = ACTION_NONE;
339    } else {
340        fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
341    }
342}
343
344static void processNode(xmlTextReaderPtr reader, struct osmdata_t *osmdata) {
345    xmlChar *name;
346    name = xmlTextReaderName(reader);
347    if (name == NULL)
348        name = xmlStrdup(BAD_CAST "--");
349       
350    switch(xmlTextReaderNodeType(reader)) {
351        case XML_READER_TYPE_ELEMENT:
352            StartElement(reader, name, osmdata);
353            if (xmlTextReaderIsEmptyElement(reader))
354                EndElement(name, osmdata); /* No end_element for self closing tags! */
355            break;
356        case XML_READER_TYPE_END_ELEMENT:
357            EndElement(name, osmdata);
358            break;
359        case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
360            /* Ignore */
361            break;
362        default:
363            fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
364            break;
365    }
366
367    xmlFree(name);
368}
369
370int streamFileXML2(char *filename, int sanitize, struct osmdata_t *osmdata) {
371    xmlTextReaderPtr reader;
372    int ret = 0;
373
374    if (sanitize)
375        reader = sanitizerOpen(filename);
376    else
377        reader = inputUTF8(filename);
378
379    if (reader != NULL) {
380        ret = xmlTextReaderRead(reader);
381        while (ret == 1) {
382          processNode(reader, osmdata);
383            ret = xmlTextReaderRead(reader);
384        }
385
386        if (ret != 0) {
387            fprintf(stderr, "%s : failed to parse\n", filename);
388            return ret;
389        }
390
391        xmlFreeTextReader(reader);
392    } else {
393        fprintf(stderr, "Unable to open %s\n", filename);
394        return 1;
395    }
396    return 0;
397}
398
Note: See TracBrowser for help on using the repository browser.