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

Last change on this file since 28719 was 26532, checked in by frederik, 8 years ago

revert r26083 - lat/lon is required on DELETE in case you are working with a bbox.
Should really be done by applying "if not given, assume lat/lon to be outside box"
logic if someone feels like it.

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