From 481271cb76a4a297bebbf6e4ceb81b5236155fb2 Mon Sep 17 00:00:00 2001 From: Hermann Kraus Date: Mon, 5 Mar 2012 16:49:54 +0100 Subject: [PATCH] Add new XML data structure and modify XML parser to work with this structure. --- include/mapnik/xml_tree.hpp | 78 ++++++++++++++++++++++++++++ src/build.py | 1 + src/libxml2_loader.cpp | 100 ++++++++++++++++-------------------- src/xml_tree.cpp | 87 +++++++++++++++++++++++++++++++ 4 files changed, 209 insertions(+), 57 deletions(-) create mode 100644 include/mapnik/xml_tree.hpp create mode 100644 src/xml_tree.cpp diff --git a/include/mapnik/xml_tree.hpp b/include/mapnik/xml_tree.hpp new file mode 100644 index 000000000..b34bb9376 --- /dev/null +++ b/include/mapnik/xml_tree.hpp @@ -0,0 +1,78 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_XML_TREE_H +#define MAPNIK_XML_TREE_H + +#include +#include +#include + +namespace mapnik +{ +class xml_tree; + +class xml_attribute +{ +public: + std::string value; + bool processed; +}; + +class xml_node +{ +public: + xml_node(xml_tree &tree, std::string name, unsigned line=0, bool text_node = false); + + std::string name() const; + std::string text() const; + + xml_node &add_child(std::string name, unsigned line=0, bool text_node = false); + void add_attribute(std::string name, std::string value); + void set_processed(bool processed); +private: + xml_tree &tree_; + std::string name_; + std::list children_; + std::map attributes_; + bool text_node_; + unsigned line_; + bool processed_; + +}; + +class xml_tree +{ +public: + xml_tree(); + void set_filename(std::string fn); + std::string filename() const; + xml_node &node(); +private: + xml_node node_; + std::string file_; + //TODO: Grammars +}; + +} //ns mapnik + +#endif // MAPNIK_XML_TREE_H diff --git a/src/build.py b/src/build.py index c25bc2fb5..b19789d3e 100644 --- a/src/build.py +++ b/src/build.py @@ -178,6 +178,7 @@ source = Split( text_placements/list.cpp text_placements/simple.cpp text_properties.cpp + xml_tree.cpp """ ) diff --git a/src/libxml2_loader.cpp b/src/libxml2_loader.cpp index c4111696f..f67f0e0db 100644 --- a/src/libxml2_loader.cpp +++ b/src/libxml2_loader.cpp @@ -22,26 +22,27 @@ #ifdef HAVE_LIBXML2 +// mapnik #include - +#include #include +// boost #include -#include #include #include +// libxml #include #include #include #include +// stl #include -using boost::property_tree::ptree; using namespace std; -//#define DEFAULT_OPTIONS (XML_PARSE_NOENT | XML_PARSE_NOBLANKS | XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA) #define DEFAULT_OPTIONS (XML_PARSE_NOERROR | XML_PARSE_NOENT | XML_PARSE_NOBLANKS | XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA) namespace mapnik @@ -50,14 +51,14 @@ class libxml2_loader : boost::noncopyable { public: libxml2_loader(const char *encoding = NULL, int options = DEFAULT_OPTIONS, const char *url = NULL) : - ctx_( 0 ), - encoding_( encoding ), - options_( options ), - url_( url ) + ctx_(0), + encoding_(encoding), + options_(options), + url_(url) { LIBXML_TEST_VERSION; ctx_ = xmlNewParserCtxt(); - if ( ! ctx_ ) + if (!ctx_) { throw std::runtime_error("Failed to create parser context."); } @@ -71,19 +72,20 @@ public: } } - void load( const std::string & filename, ptree & pt ) + void load(const std::string & filename, xml_node &node) { boost::filesystem::path path(filename); - if ( !boost::filesystem::exists( path ) ) { + if (!boost::filesystem::exists(path)) + { throw config_error(string("Could not load map file '") + filename + "': File does not exist"); } xmlDocPtr doc = xmlCtxtReadFile(ctx_, filename.c_str(), encoding_, options_); - if ( !doc ) + if (!doc) { - xmlError * error = xmlCtxtGetLastError( ctx_ ); + xmlError * error = xmlCtxtGetLastError(ctx_); if (error) { std::ostringstream os; @@ -91,13 +93,13 @@ public: os << ": " << std::endl << error->message; // remove CR std::string msg = os.str().substr(0, os.str().size() - 1); - config_error ex( msg ); + config_error ex(msg); os.str(""); os << "(encountered in file '" << error->file << "' at line " << error->line << ")"; - ex.append_context( os.str() ); + ex.append_context(os.str()); throw ex; } @@ -110,21 +112,21 @@ public: << std::endl; } */ - load(doc, pt); + load(doc, node); } - void load( const int fd, ptree & pt ) + void load(const int fd, xml_node &node) { xmlDocPtr doc = xmlCtxtReadFd(ctx_, fd, url_, encoding_, options_); - load(doc, pt); + load(doc, node); } - void load_string( const std::string & buffer, ptree & pt, std::string const & base_path ) + void load_string(const std::string & buffer, xml_node &node, std::string const & base_path ) { if (!base_path.empty()) { boost::filesystem::path path(base_path); - if ( ! boost::filesystem::exists( path ) ) { + if (!boost::filesystem::exists(path)) { throw config_error(string("Could not locate base_path '") + base_path + "': file or directory does not exist"); } @@ -132,12 +134,12 @@ public: xmlDocPtr doc = xmlCtxtReadMemory(ctx_, buffer.data(), buffer.length(), base_path.c_str(), encoding_, options_); - load(doc, pt); + load(doc, node); } - void load( const xmlDocPtr doc, ptree & pt ) + void load(const xmlDocPtr doc, xml_node &node) { - if ( !doc ) + if (!doc) { xmlError * error = xmlCtxtGetLastError( ctx_ ); std::ostringstream os; @@ -149,7 +151,7 @@ public: throw config_error(os.str()); } - int iXIncludeReturn = xmlXIncludeProcessFlags( doc, options_ ); + int iXIncludeReturn = xmlXIncludeProcessFlags(doc, options_); if (iXIncludeReturn < 0) { @@ -157,63 +159,47 @@ public: throw config_error("XML XInclude error. One or more files failed to load."); } - xmlNode * root = xmlDocGetRootElement( doc ); - if ( ! root ) { + xmlNode * root = xmlDocGetRootElement(doc); + if (!root) { xmlFreeDoc(doc); throw config_error("XML document is empty."); } - populate_tree( root, pt ); + populate_tree(root, node); xmlFreeDoc(doc); } private: - void append_attributes( xmlAttr * attributes, ptree & pt) + void append_attributes(xmlAttr *attributes, xml_node &node) { - if (attributes) + for (; attributes; attributes = attributes->next ) { - ptree::iterator it = pt.push_back( ptree::value_type( "", ptree() )); - ptree & attr_list = it->second; - xmlAttr * cur_attr = attributes; - for (; cur_attr; cur_attr = cur_attr->next ) - { - ptree::iterator it = attr_list.push_back( - ptree::value_type( (char*)cur_attr->name, ptree() )); - it->second.put_value( (char*) cur_attr->children->content ); - } + node.add_attribute((char *)attributes->name, (char *)attributes->children->content); } } - void populate_tree( xmlNode * node, ptree & pt ) + void populate_tree(xmlNode *cur_node, xml_node &node) { - xmlNode * cur_node = node; - for (; cur_node; cur_node = cur_node->next ) { switch (cur_node->type) { case XML_ELEMENT_NODE: { - ptree::iterator it = pt.push_back( ptree::value_type( - (char*)cur_node->name, ptree() )); - append_attributes( cur_node->properties, it->second); - populate_tree( cur_node->children, it->second ); + + xml_node &new_node = node.add_child((char *)cur_node->name, cur_node->line, false); + append_attributes(cur_node->properties, new_node); + populate_tree(cur_node->children, new_node); } break; case XML_TEXT_NODE: { std::string trimmed = boost::algorithm::trim_copy(std::string((char*)cur_node->content)); - if (trimmed.empty()) break; - ptree::iterator it = pt.push_back(ptree::value_type("", ptree())); - it->second.put_value(trimmed); + if (trimmed.empty()) break; //Don't add empty text nodes + node.add_child(trimmed, cur_node->line, true); } break; case XML_COMMENT_NODE: - { - ptree::iterator it = pt.push_back( - ptree::value_type( "", ptree() )); - it->second.put_value( (char*) cur_node->content ); - } break; default: break; @@ -228,15 +214,15 @@ private: const char *url_; }; -void read_xml2( std::string const & filename, boost::property_tree::ptree & pt) +void read_xml2(std::string const & filename, xml_node &node) { libxml2_loader loader; - loader.load( filename, pt ); + loader.load(filename, node); } -void read_xml2_string( std::string const & str, boost::property_tree::ptree & pt, std::string const & base_path) +void read_xml2_string(std::string const & str, xml_node &node, std::string const & base_path) { libxml2_loader loader; - loader.load_string( str, pt, base_path ); + loader.load_string(str, node, base_path); } } // end of namespace mapnik diff --git a/src/xml_tree.cpp b/src/xml_tree.cpp new file mode 100644 index 000000000..3a05a82ac --- /dev/null +++ b/src/xml_tree.cpp @@ -0,0 +1,87 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ +#include + +namespace mapnik +{ + +xml_tree::xml_tree() + : node_(*this, "") +{ +} + +void xml_tree::set_filename(std::string fn) +{ + file_ = fn; +} + +std::string xml_tree::filename() const +{ + return file_; +} + +xml_node &xml_tree::node() +{ + return node_; +} + +/****************************************************************************/ + +xml_node::xml_node(xml_tree &tree, std::string name, unsigned line, bool text_node) + : tree_(tree), + name_(name), + text_node_(text_node), + line_(line), + processed_(false) +{ + +} + +std::string xml_node::name() const +{ + if (!text_node_) + return name_; + else + return ""; +} + +std::string xml_node::text() const +{ + if (text_node_) + return name_; + else + return "NOT A TEXT NODE"; +} + +void xml_node::set_processed(bool processed) +{ + processed_ = processed; +} + +xml_node &xml_node::add_child(std::string name, unsigned line, bool text_node) +{ + children_.push_back(xml_node(tree_, name, line, text_node)); + return children_.back(); +} + + +} //ns mapnik