2 * Hic Est Leo -- OSM XML Parser
4 * (c) 2014 Martin Mares <mj@ucw.cz>
8 #include <ucw/fastbuf.h>
18 static void parse_tag(struct xml_context *ctx, struct osm_object *o, struct xml_node *t)
20 char *tag_k = xml_attr_value(ctx, t, "k");
21 char *tag_v = xml_attr_value(ctx, t, "v");
23 die("Object %ju has malformed tag", (uintmax_t) o->id);
24 osm_obj_add_tag(o, tag_k, tag_v);
27 static void parse_node(struct xml_context *ctx, struct xml_node *e)
29 char *attr_id = xml_attr_value(ctx, e, "id");
31 die("Node with no id");
33 char *attr_vis = xml_attr_value(ctx, e, "visible");
34 if (attr_vis && strcmp(attr_vis, "true"))
36 msg(L_DEBUG, "Node %s invisible", attr_id);
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);
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);
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);
54 static void parse_way(struct xml_context *ctx, struct xml_node *e)
56 char *attr_id = xml_attr_value(ctx, e, "id");
58 die("Way with no id");
60 char *attr_vis = xml_attr_value(ctx, e, "visible");
61 if (attr_vis && strcmp(attr_vis, "true"))
63 msg(L_DEBUG, "Way %s invisible", attr_id);
67 struct osm_way *w = osm_way_new(osm_parse_id(attr_id));
69 XML_NODE_FOR_EACH(t, e)
70 if (t->type == XML_NODE_ELEM)
72 if (!strcmp(t->name, "tag"))
73 parse_tag(ctx, &w->o, t);
74 else if (!strcmp(t->name, "nd"))
76 char *nd_ref = xml_attr_value(ctx, t, "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));
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);
87 static void parse_relation(struct xml_context *ctx, struct xml_node *e)
89 char *attr_id = xml_attr_value(ctx, e, "id");
91 die("Relation with no id");
93 char *attr_vis = xml_attr_value(ctx, e, "visible");
94 if (attr_vis && strcmp(attr_vis, "true"))
96 msg(L_DEBUG, "Relation %s invisible", attr_id);
100 struct osm_relation *r = osm_relation_new(osm_parse_id(attr_id));
102 XML_NODE_FOR_EACH(t, e)
103 if (t->type == XML_NODE_ELEM)
105 if (!strcmp(t->name, "tag"))
106 parse_tag(ctx, &r->o, t);
107 else if (!strcmp(t->name, "member"))
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);
116 enum osm_object_type type;
117 if (!strcmp(m_type, "node"))
118 type = OSM_TYPE_NODE;
119 else if (!strcmp(m_type, "way"))
121 else if (!strcmp(m_type, "relation"))
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);
129 msg(L_WARN, "Relation %ju refers to member %ju of unknown type %s", (uintmax_t) r->o.id, (uintmax_t) ref, m_type);
133 struct osm_object *o = osm_obj_find_by_id(type, ref);
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);
140 osm_relation_add_member(r, o, m_role);
145 static void h_error(struct xml_context *ctx)
147 fprintf(stderr, "%s at %u: %s\n", (ctx->err_code < XML_ERR_ERROR) ? "warn" : "error", xml_row(ctx), ctx->err_msg);
152 static void h_stag(struct xml_context *ctx)
154 printf("STAG %s\n", ctx->node->name);
155 if (!strcmp(ctx->node->name, "node"))
157 ctx->flags &= ~XML_REPORT_TAGS;
158 ctx->flags |= XML_ALLOC_ALL;
162 static void h_etag(struct xml_context *ctx)
164 printf("ETAG %s\n", ctx->node->name);
169 void osm_xml_parse(const char *name)
171 struct xml_context ctx;
173 ctx.h_warn = ctx.h_error = ctx.h_fatal = h_error;
174 xml_push_fastbuf(&ctx, bopen_file(name, O_RDONLY, NULL));
177 ctx.flags |= XML_REPORT_TAGS;
185 while (state = xml_next(&ctx))
189 printf("STAG %s\n", ctx.node->name);
190 if (!strcmp(ctx.node->name, "node"))
192 ctx.pull = XML_PULL_ETAG;
193 ctx.flags |= XML_ALLOC_CHARS | XML_ALLOC_TAGS;
197 printf("ETAG %s\n", ctx.node->name);
198 if (!strcmp(ctx.node->name, "node"))
200 ctx.pull = XML_PULL_STAG | XML_PULL_ETAG;
201 ctx.flags &= ~(XML_ALLOC_CHARS | XML_ALLOC_TAGS);
207 ctx.flags |= XML_ALLOC_ALL;
211 die("Fatal error in XML parser");
213 struct xml_node *root = ctx.dom;
215 XML_NODE_FOR_EACH(e, root)
216 if (e->type == XML_NODE_ELEM)
218 if (!strcmp(e->name, "node"))
220 else if (!strcmp(e->name, "way"))
222 else if (!strcmp(e->name, "relation"))
223 parse_relation(&ctx, e);