Osmium  0.1
include/osmium/input/xml.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines