Osmium
0.1
|
00001 #ifndef OSMIUM_INPUT_XML_HPP 00002 #define OSMIUM_INPUT_XML_HPP 00003 00004 /* 00005 00006 Copyright 2011 Jochen Topf <jochen@topf.org> and others (see README). 00007 00008 This file is part of Osmium (https://github.com/joto/osmium). 00009 00010 Osmium is free software: you can redistribute it and/or modify it under the 00011 terms of the GNU Lesser General Public License or (at your option) the GNU 00012 General Public License as published by the Free Software Foundation, either 00013 version 3 of the Licenses, or (at your option) any later version. 00014 00015 Osmium is distributed in the hope that it will be useful, but WITHOUT ANY 00016 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 00017 PARTICULAR PURPOSE. See the GNU Lesser General Public License and the GNU 00018 General Public License for more details. 00019 00020 You should have received a copy of the Licenses along with Osmium. If not, see 00021 <http://www.gnu.org/licenses/>. 00022 00023 */ 00024 00025 #include <cstdio> 00026 #include <cstdlib> 00027 #include <iostream> 00028 #include <string> 00029 #include <unistd.h> 00030 #include <cstring> 00031 #include <sstream> 00032 00033 #include <expat.h> 00034 00035 namespace Osmium { 00036 00037 namespace Input { 00038 00047 template <class THandler> 00048 class XML : public Base<THandler> { 00049 00050 public: 00051 00058 XML(Osmium::OSMFile& file, THandler& handler) : Base<THandler>(file, handler), m_current_object(NULL), m_in_delete_section(false) { 00059 } 00060 00061 void parse() { 00062 int done; 00063 00064 XML_Parser parser = XML_ParserCreate(0); 00065 if (!parser) { 00066 throw std::runtime_error("Error creating parser"); 00067 } 00068 00069 XML_SetUserData(parser, this); 00070 00071 XML_SetElementHandler(parser, Osmium::Input::XML<THandler>::start_element_wrapper, Osmium::Input::XML<THandler>::end_element_wrapper); 00072 00073 try { 00074 do { 00075 void* buffer = XML_GetBuffer(parser, c_buffer_size); 00076 if (buffer == 0) { 00077 throw std::runtime_error("out of memory"); 00078 } 00079 00080 int result = read(this->get_fd(), buffer, c_buffer_size); 00081 if (result < 0) { 00082 exit(1); 00083 } 00084 done = (result == 0); 00085 if (XML_ParseBuffer(parser, result, done) == XML_STATUS_ERROR) { 00086 XML_Error errorCode = XML_GetErrorCode(parser); 00087 long errorLine = XML_GetCurrentLineNumber(parser); 00088 long errorCol = XML_GetCurrentColumnNumber(parser); 00089 const XML_LChar *errorString = XML_ErrorString(errorCode); 00090 00091 std::stringstream errorDesc; 00092 errorDesc << "XML parsing error at line " << errorLine << ":" << errorCol; 00093 errorDesc << ": " << errorString; 00094 throw std::runtime_error(errorDesc.str()); 00095 } 00096 } while (!done); 00097 XML_ParserFree(parser); 00098 00099 this->call_after_and_before_on_handler(UNKNOWN); 00100 } catch (Osmium::Input::StopReading) { 00101 // if a handler says to stop reading, we do 00102 } 00103 this->call_final_on_handler(); 00104 } 00105 00106 private: 00107 00108 static const int c_buffer_size = 10240; 00109 00110 Osmium::OSM::Object* m_current_object; 00111 00116 bool m_in_delete_section; 00117 00118 static void XMLCALL start_element_wrapper(void* data, const XML_Char* element, const XML_Char** attrs) { 00119 ((Osmium::Input::XML<THandler> *)data)->start_element(element, attrs); 00120 } 00121 00122 static void XMLCALL end_element_wrapper(void* data, const XML_Char* element) { 00123 ((Osmium::Input::XML<THandler> *)data)->end_element(element); 00124 } 00125 00126 void init_object(Osmium::OSM::Object& obj, const XML_Char** attrs) { 00127 if (m_in_delete_section) { 00128 obj.visible(false); 00129 } 00130 m_current_object = &obj; 00131 for (int count = 0; attrs[count]; count += 2) { 00132 if (!strcmp(attrs[count], "lon")) { 00133 if (this->m_node) { 00134 this->m_node->set_x(atof(attrs[count+1])); 00135 } 00136 } else if (!strcmp(attrs[count], "lat")) { 00137 if (this->m_node) { 00138 this->m_node->set_y(atof(attrs[count+1])); 00139 } 00140 } else { 00141 m_current_object->set_attribute(attrs[count], attrs[count+1]); 00142 } 00143 } 00144 } 00145 00146 void start_element(const XML_Char* element, const XML_Char** attrs) { 00147 // order in the following "if" statements is based on frequency of tags in planet file 00148 if (!strcmp(element, "nd")) { 00149 for (int count = 0; attrs[count]; count += 2) { 00150 if (!strcmp(attrs[count], "ref")) { 00151 this->m_way->add_node(atoll(attrs[count+1])); 00152 } 00153 } 00154 } else if (!strcmp(element, "node")) { 00155 this->call_after_and_before_on_handler(NODE); 00156 init_object(this->prepare_node(), attrs); 00157 } else if (!strcmp(element, "tag")) { 00158 const char *key = "", *value = ""; 00159 for (int count = 0; attrs[count]; count += 2) { 00160 if (attrs[count][0] == 'k' && attrs[count][1] == 0) { 00161 key = attrs[count+1]; 00162 } 00163 if (attrs[count][0] == 'v' && attrs[count][1] == 0) { 00164 value = attrs[count+1]; 00165 } 00166 } 00167 // XXX assert key, value exist 00168 if (m_current_object) { 00169 m_current_object->tags().add(key, value); 00170 } 00171 } else if (!strcmp(element, "way")) { 00172 this->call_after_and_before_on_handler(WAY); 00173 init_object(this->prepare_way(), attrs); 00174 } else if (!strcmp(element, "member")) { 00175 char type = 'x'; 00176 uint64_t ref = 0; 00177 const char *role = ""; 00178 for (int count = 0; attrs[count]; count += 2) { 00179 if (!strcmp(attrs[count], "type")) { 00180 type = (char)attrs[count+1][0]; 00181 } else if (!strcmp(attrs[count], "ref")) { 00182 ref = atoll(attrs[count+1]); 00183 } else if (!strcmp(attrs[count], "role")) { 00184 role = (char *)attrs[count+1]; 00185 } 00186 } 00187 // XXX assert type, ref, role are set 00188 if (m_current_object && this->m_relation) { 00189 this->m_relation->add_member(type, ref, role); 00190 } 00191 } else if (!strcmp(element, "relation")) { 00192 this->call_after_and_before_on_handler(RELATION); 00193 init_object(this->prepare_relation(), attrs); 00194 } else if (!strcmp(element, "bounds")) { 00195 Osmium::OSM::Position min; 00196 Osmium::OSM::Position max; 00197 for (int count = 0; attrs[count]; count += 2) { 00198 if (!strcmp(attrs[count], "minlon")) { 00199 min.lon(atof(attrs[count+1])); 00200 } else if (!strcmp(attrs[count], "minlat")) { 00201 min.lat(atof(attrs[count+1])); 00202 } else if (!strcmp(attrs[count], "maxlon")) { 00203 max.lon(atof(attrs[count+1])); 00204 } else if (!strcmp(attrs[count], "maxlat")) { 00205 max.lat(atof(attrs[count+1])); 00206 } 00207 } 00208 this->meta().bounds().extend(min).extend(max); 00209 } else if (!strcmp(element, "delete")) { 00210 m_in_delete_section = true; 00211 } 00212 } 00213 00214 void end_element(const XML_Char* element) { 00215 if (!strcmp(element, "node")) { 00216 this->call_node_on_handler(); 00217 m_current_object = NULL; 00218 } else if (!strcmp(element, "way")) { 00219 this->call_way_on_handler(); 00220 m_current_object = NULL; 00221 } else if (!strcmp(element, "relation")) { 00222 this->call_relation_on_handler(); 00223 m_current_object = NULL; 00224 } else if (!strcmp(element, "delete")) { 00225 m_in_delete_section = false; 00226 } 00227 } 00228 00229 }; // class XML 00230 00231 } // namespace Input 00232 00233 } // namespace Osmium 00234 00235 #endif // OSMIUM_INPUT_XML_HPP