]> mj.ucw.cz Git - leo.git/blob - xml.c
Support for reading of shape files (partial)
[leo.git] / xml.c
1 /*
2  *      Hic Est Leo -- OSM XML Parser
3  *
4  *      (c) 2014 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <ucw/lib.h>
8 #include <ucw/fastbuf.h>
9 #include <xml/xml.h>
10
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #include "leo.h"
16 #include "osm.h"
17
18 static void parse_tag(struct xml_context *ctx, struct osm_object *o, struct xml_node *t)
19 {
20   char *tag_k = xml_attr_value(ctx, t, "k");
21   char *tag_v = xml_attr_value(ctx, t, "v");
22   if (!tag_k || !tag_v)
23     die("Object %ju has malformed tag", (uintmax_t) o->id);
24   osm_obj_add_tag(o, tag_k, tag_v);
25 }
26
27 static void parse_node(struct xml_context *ctx, struct xml_node *e)
28 {
29   char *attr_id = xml_attr_value(ctx, e, "id");
30   if (!attr_id)
31     die("Node with no id");
32
33   char *attr_vis = xml_attr_value(ctx, e, "visible");
34   if (attr_vis && strcmp(attr_vis, "true"))
35     {
36       msg(L_DEBUG, "Node %s invisible", attr_id);
37       return;
38     }
39
40   char *attr_lat = xml_attr_value(ctx, e, "lat");
41   char *attr_lon = xml_attr_value(ctx, e, "lon");
42   if (!attr_lat || !attr_lon)
43     die("Node %s has mandatory attributes missing", attr_id);
44
45   struct osm_node *n = osm_node_new(osm_parse_id(attr_id));
46   n->x = atof(attr_lon);
47   n->y = atof(attr_lat);
48
49   XML_NODE_FOR_EACH(t, e)
50     if (t->type == XML_NODE_ELEM && !strcmp(t->name, "tag"))
51       parse_tag(ctx, &n->o, t);
52 }
53
54 static void parse_way(struct xml_context *ctx, struct xml_node *e)
55 {
56   char *attr_id = xml_attr_value(ctx, e, "id");
57   if (!attr_id)
58     die("Way with no id");
59
60   char *attr_vis = xml_attr_value(ctx, e, "visible");
61   if (attr_vis && strcmp(attr_vis, "true"))
62     {
63       msg(L_DEBUG, "Way %s invisible", attr_id);
64       return;
65     }
66
67   struct osm_way *w = osm_way_new(osm_parse_id(attr_id));
68
69   XML_NODE_FOR_EACH(t, e)
70     if (t->type == XML_NODE_ELEM)
71       {
72         if (!strcmp(t->name, "tag"))
73           parse_tag(ctx, &w->o, t);
74         else if (!strcmp(t->name, "nd"))
75           {
76             char *nd_ref = xml_attr_value(ctx, t, "ref");
77             if (!nd_ref)
78               die("Way %s has malformed ref", attr_id);
79             struct osm_object *o = osm_obj_find_by_id(OSM_TYPE_NODE, osm_parse_id(nd_ref));
80             if (!o)
81               die("Way %ju refers to unknown node %s", (uintmax_t) w->o.id, nd_ref);
82             osm_way_add_node(w, (struct osm_node *) o);
83           }
84       }
85 }
86
87 static void parse_relation(struct xml_context *ctx, struct xml_node *e)
88 {
89   char *attr_id = xml_attr_value(ctx, e, "id");
90   if (!attr_id)
91     die("Relation with no id");
92
93   char *attr_vis = xml_attr_value(ctx, e, "visible");
94   if (attr_vis && strcmp(attr_vis, "true"))
95     {
96       msg(L_DEBUG, "Relation %s invisible", attr_id);
97       return;
98     }
99
100   struct osm_relation *r = osm_relation_new(osm_parse_id(attr_id));
101
102   XML_NODE_FOR_EACH(t, e)
103     if (t->type == XML_NODE_ELEM)
104       {
105         if (!strcmp(t->name, "tag"))
106           parse_tag(ctx, &r->o, t);
107         else if (!strcmp(t->name, "member"))
108           {
109             char *m_role = xml_attr_value(ctx, t, "role");
110             char *m_ref = xml_attr_value(ctx, t, "ref");
111             char *m_type = xml_attr_value(ctx, t, "type");
112             if (!m_role || !m_ref || !m_type)
113               die("Relation %ju has malformed member", (uintmax_t) r->o.id);
114             osm_id_t ref = osm_parse_id(m_ref);
115
116             enum osm_object_type type;
117             if (!strcmp(m_type, "node"))
118               type = OSM_TYPE_NODE;
119             else if (!strcmp(m_type, "way"))
120               type = OSM_TYPE_WAY;
121             else if (!strcmp(m_type, "relation"))
122               {
123                 type = OSM_TYPE_RELATION;
124                 // Since the order of objects is topological, we need not worry about cycles
125                 // msg(L_DEBUG, "Relation inside relation (%ju inside %ju)", (uintmax_t) o->id, (uintmax_t) r->o.id);
126               }
127             else
128               {
129                 msg(L_WARN, "Relation %ju refers to member %ju of unknown type %s", (uintmax_t) r->o.id, (uintmax_t) ref, m_type);
130                 continue;
131               }
132
133             struct osm_object *o = osm_obj_find_by_id(type, ref);
134             if (!o)
135               {
136                 // This is a standard situation, so warn only when debugging
137                 // msg(L_WARN, "Relation %ju refers to unknown member node %s", (uintmax_t) ref, m_ref);
138                 continue;
139               }
140             osm_relation_add_member(r, o, m_role);
141           }
142       }
143 }
144
145 static void h_error(struct xml_context *ctx)
146 {
147   fprintf(stderr, "%s at %u: %s\n", (ctx->err_code < XML_ERR_ERROR) ? "warn" : "error", xml_row(ctx), ctx->err_msg);
148 }
149
150 #if 0
151
152 static void h_stag(struct xml_context *ctx)
153 {
154   printf("STAG %s\n", ctx->node->name);
155   if (!strcmp(ctx->node->name, "node"))
156     {
157       ctx->flags &= ~XML_REPORT_TAGS;
158       ctx->flags |= XML_ALLOC_ALL;
159     }
160 }
161
162 static void h_etag(struct xml_context *ctx)
163 {
164   printf("ETAG %s\n", ctx->node->name);
165 }
166
167 #endif
168
169 void osm_xml_parse(const char *name)
170 {
171   struct xml_context ctx;
172   xml_init(&ctx);
173   ctx.h_warn = ctx.h_error = ctx.h_fatal = h_error;
174   xml_push_fastbuf(&ctx, bopen_file(name, O_RDONLY, NULL));
175
176 #if 0
177   ctx.flags |= XML_REPORT_TAGS;
178   ctx.h_stag = h_stag;
179   ctx.h_etag = h_etag;
180   xml_parse(&ctx);
181 #endif
182
183 #if 0
184   uns state;
185   while (state = xml_next(&ctx))
186     switch (state)
187       {
188       case XML_STATE_STAG:
189         printf("STAG %s\n", ctx.node->name);
190         if (!strcmp(ctx.node->name, "node"))
191           {
192             ctx.pull = XML_PULL_ETAG;
193             ctx.flags |= XML_ALLOC_CHARS | XML_ALLOC_TAGS;
194           }
195         break;
196       case XML_STATE_ETAG:
197         printf("ETAG %s\n", ctx.node->name);
198         if (!strcmp(ctx.node->name, "node"))
199           {
200             ctx.pull = XML_PULL_STAG | XML_PULL_ETAG;
201             ctx.flags &= ~(XML_ALLOC_CHARS | XML_ALLOC_TAGS);
202           }
203         break;
204       }
205 #endif
206
207   ctx.flags |= XML_ALLOC_ALL;
208   xml_parse(&ctx);
209
210   if (ctx.err_code)
211     die("Fatal error in XML parser");
212
213   struct xml_node *root = ctx.dom;
214   ASSERT(root);
215   XML_NODE_FOR_EACH(e, root)
216     if (e->type == XML_NODE_ELEM)
217       {
218         if (!strcmp(e->name, "node"))
219           parse_node(&ctx, e);
220         else if (!strcmp(e->name, "way"))
221           parse_way(&ctx, e);
222         else if (!strcmp(e->name, "relation"))
223           parse_relation(&ctx, e);
224       }
225
226   xml_cleanup(&ctx);
227 }