2 * Hic Est Leo -- OSM XML Parser
4 * (c) 2014--2015 Martin Mares <mj@ucw.cz>
12 #include <ucw/fastbuf.h>
13 #include <ucw-xml/xml.h>
19 static void parse_tag(struct xml_context *ctx, struct osm_object *o, struct xml_node *t)
21 char *tag_k = xml_attr_value(ctx, t, "k");
22 char *tag_v = xml_attr_value(ctx, t, "v");
24 die("Object %ju has malformed tag", (uintmax_t) o->id);
25 osm_obj_add_tag(o, tag_k, tag_v);
28 static void parse_node(struct xml_context *ctx, struct xml_node *e)
30 char *attr_id = xml_attr_value(ctx, e, "id");
32 die("Node with no id");
34 char *attr_vis = xml_attr_value(ctx, e, "visible");
35 if (attr_vis && strcmp(attr_vis, "true"))
37 msg(L_DEBUG, "Node %s invisible", attr_id);
41 char *attr_lat = xml_attr_value(ctx, e, "lat");
42 char *attr_lon = xml_attr_value(ctx, e, "lon");
43 if (!attr_lat || !attr_lon)
44 die("Node %s has mandatory attributes missing", attr_id);
46 struct osm_node *n = osm_node_new(osm_parse_id(attr_id));
47 n->x = atof(attr_lon);
48 n->y = atof(attr_lat);
50 XML_NODE_FOR_EACH(t, e)
51 if (t->type == XML_NODE_ELEM && !strcmp(t->name, "tag"))
52 parse_tag(ctx, &n->o, t);
55 static void parse_way(struct xml_context *ctx, struct xml_node *e)
57 char *attr_id = xml_attr_value(ctx, e, "id");
59 die("Way with no id");
61 char *attr_vis = xml_attr_value(ctx, e, "visible");
62 if (attr_vis && strcmp(attr_vis, "true"))
64 msg(L_DEBUG, "Way %s invisible", attr_id);
68 struct osm_way *w = osm_way_new(osm_parse_id(attr_id));
70 XML_NODE_FOR_EACH(t, e)
71 if (t->type == XML_NODE_ELEM)
73 if (!strcmp(t->name, "tag"))
74 parse_tag(ctx, &w->o, t);
75 else if (!strcmp(t->name, "nd"))
77 char *nd_ref = xml_attr_value(ctx, t, "ref");
79 die("Way %s has malformed ref", attr_id);
80 struct osm_object *o = osm_obj_find_by_id(OSM_TYPE_NODE, osm_parse_id(nd_ref));
82 die("Way %ju refers to unknown node %s", (uintmax_t) w->o.id, nd_ref);
83 osm_way_add_node(w, (struct osm_node *) o);
88 static void parse_relation(struct xml_context *ctx, struct xml_node *e)
90 char *attr_id = xml_attr_value(ctx, e, "id");
92 die("Relation with no id");
94 char *attr_vis = xml_attr_value(ctx, e, "visible");
95 if (attr_vis && strcmp(attr_vis, "true"))
97 msg(L_DEBUG, "Relation %s invisible", attr_id);
101 struct osm_relation *r = osm_relation_new(osm_parse_id(attr_id));
103 XML_NODE_FOR_EACH(t, e)
104 if (t->type == XML_NODE_ELEM)
106 if (!strcmp(t->name, "tag"))
107 parse_tag(ctx, &r->o, t);
108 else if (!strcmp(t->name, "member"))
110 char *m_role = xml_attr_value(ctx, t, "role");
111 char *m_ref = xml_attr_value(ctx, t, "ref");
112 char *m_type = xml_attr_value(ctx, t, "type");
113 if (!m_role || !m_ref || !m_type)
114 die("Relation %ju has malformed member", (uintmax_t) r->o.id);
115 osm_id_t ref = osm_parse_id(m_ref);
117 enum osm_object_type type;
118 if (!strcmp(m_type, "node"))
119 type = OSM_TYPE_NODE;
120 else if (!strcmp(m_type, "way"))
122 else if (!strcmp(m_type, "relation"))
124 type = OSM_TYPE_RELATION;
125 // Since the order of objects is topological, we need not worry about cycles
126 // msg(L_DEBUG, "Relation inside relation (%ju inside %ju)", (uintmax_t) o->id, (uintmax_t) r->o.id);
130 msg(L_WARN, "Relation %ju refers to member %ju of unknown type %s", (uintmax_t) r->o.id, (uintmax_t) ref, m_type);
134 struct osm_object *o = osm_obj_find_by_id(type, ref);
137 // This is a standard situation, so warn only when debugging
138 // msg(L_WARN, "Relation %ju refers to unknown member node %s", (uintmax_t) ref, m_ref);
141 osm_relation_add_member(r, o, m_role);
146 static void h_error(struct xml_context *ctx)
148 fprintf(stderr, "%s at %u: %s\n", (ctx->err_code < XML_ERR_ERROR) ? "warn" : "error", xml_row(ctx), ctx->err_msg);
151 static void parse_element(struct xml_context *ctx, struct xml_node *e)
153 // JOSM marks deleted, but not uploaded, objects
154 char *action = xml_attr_value(ctx, e, "action");
155 if (action && !strcmp(action, "delete"))
158 if (!strcmp(e->name, "node"))
160 else if (!strcmp(e->name, "way"))
162 else if (!strcmp(e->name, "relation"))
163 parse_relation(ctx, e);
166 void osm_xml_parse(const char *name)
168 struct xml_context xml_ctx, *ctx = &xml_ctx;
170 ctx->h_warn = ctx->h_error = ctx->h_fatal = h_error;
171 xml_push_fastbuf(ctx, bopen_file(name, O_RDONLY, NULL));
174 while (state = xml_next_state(ctx, XML_PULL_STAG))
175 if (state == XML_STATE_STAG)
177 DBG("Level 1 tag <%s>", ctx->node->name);
178 if (!strcmp(ctx->node->name, "osm"))
180 DBG("Switched to level 2");
181 while ((state = xml_next_state(ctx, XML_PULL_STAG | XML_PULL_ETAG)) == XML_STATE_STAG)
183 ctx->flags |= XML_ALLOC_CHARS | XML_ALLOC_TAGS;
184 if (xml_skip_element(ctx) == XML_STATE_ETAG)
186 DBG("Level 2 tag <%s>", ctx->node->name);
187 parse_element(ctx, ctx->node);
190 DBG("Exited level 2 in state %u", state);
193 xml_skip_element(ctx);
197 die("Fatal error in XML parser");