Merge remote-tracking branch 'origin/master'

This commit is contained in:
Artem Pavlenko 2012-03-13 16:44:36 +00:00
commit 385ca5b5b5
87 changed files with 1982 additions and 1730 deletions

View file

@ -40,15 +40,15 @@
using namespace mapnik; using namespace mapnik;
/* Notes: /* Notes:
Overriding functions in inherited classes: Overriding functions in inherited classes:
boost.python documentation doesn't really tell you how to do it. boost.python documentation doesn't really tell you how to do it.
But this helps: But this helps:
http://www.gamedev.net/topic/446225-inheritance-in-boostpython/ http://www.gamedev.net/topic/446225-inheritance-in-boostpython/
register_ptr_to_python is required for wrapped classes, but not for unwrapped. register_ptr_to_python is required for wrapped classes, but not for unwrapped.
Functions don't have to be members of the class, but can also be Functions don't have to be members of the class, but can also be
normal functions taking a ref to the class as first parameter. normal functions taking a ref to the class as first parameter.
*/ */
namespace { namespace {

View file

@ -103,7 +103,7 @@ struct python_optional : public boost::noncopyable
/** This class works around a bug in boost python. /** This class works around a bug in boost python.
See http://osdir.com/ml/python.c++/2003-11/msg00158.html See http://osdir.com/ml/python.c++/2003-11/msg00158.html
*/ */
template <typename T, typename X1 = boost::python::detail::not_specified, typename X2 = boost::python::detail::not_specified, typename X3 = boost::python::detail::not_specified> template <typename T, typename X1 = boost::python::detail::not_specified, typename X2 = boost::python::detail::not_specified, typename X3 = boost::python::detail::not_specified>
class class_with_converter : public boost::python::class_<T, X1, X2, X3> class class_with_converter : public boost::python::class_<T, X1, X2, X3>
{ {

View file

@ -0,0 +1,90 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2011 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_BOOLEAN_HPP
#define MAPNIK_BOOLEAN_HPP
#include <istream>
namespace mapnik
{
/** Helper for class bool */
class boolean {
public:
boolean(): b_(false) {}
boolean(bool b) : b_(b) {}
boolean(boolean const& b) : b_(b.b_) {}
operator bool() const
{
return b_;
}
boolean & operator = (boolean const& other)
{
b_ = other.b_;
return * this;
}
boolean & operator = (bool other)
{
b_ = other;
return * this;
}
private:
bool b_;
};
/** Special stream input operator for boolean values */
template <typename charT, typename traits>
std::basic_istream<charT, traits> &
operator >> ( std::basic_istream<charT, traits> & s, boolean & b )
{
std::string word;
s >> word;
if ( s )
{
if ( word == "true" || word == "yes" || word == "on" ||
word == "1")
{
b = true;
}
else if ( word == "false" || word == "no" || word == "off" ||
word == "0")
{
b = false;
}
else
{
s.setstate( std::ios::failbit );
}
}
return s;
}
template <typename charT, typename traits>
std::basic_ostream<charT, traits> &
operator << ( std::basic_ostream<charT, traits> & s, boolean const& b )
{
s << ( b ? "true" : "false" );
return s;
}
}
#endif // MAPNIK_BOOLEAN_HPP

View file

@ -137,6 +137,14 @@ public:
std::string to_hex_string() const; std::string to_hex_string() const;
}; };
template <typename charT, typename traits>
std::basic_ostream<charT, traits> &
operator << ( std::basic_ostream<charT, traits> & s, mapnik::color const& c )
{
std::string hex_string( c.to_string() );
s << hex_string;
return s;
}
} }

View file

@ -25,134 +25,26 @@
// mapnik // mapnik
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/color.hpp>
#include <mapnik/config_error.hpp>
// boost // boost
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/version.hpp>
// boost 1.41 -> 1.44 compatibility, to be removed in mapnik 2.1 (dane)
#if BOOST_VERSION >= 104500
#include <mapnik/css_color_grammar.hpp>
namespace mapnik { namespace mapnik {
class color;
template <typename Iterator> struct css_color_grammar;
class MAPNIK_DECL color_factory : boost::noncopyable class MAPNIK_DECL color_factory : boost::noncopyable
{ {
public: public:
static void init_from_string(color & c, std::string const& css_color) static void init_from_string(color & c, std::string const& css_color);
{
typedef std::string::const_iterator iterator_type;
typedef mapnik::css_color_grammar<iterator_type> css_color_grammar;
css_color_grammar g;
iterator_type first = css_color.begin();
iterator_type last = css_color.end();
bool result =
boost::spirit::qi::phrase_parse(first,
last,
g,
boost::spirit::ascii::space,
c);
if (!result)
{
throw config_error(std::string("Failed to parse color value: ") +
"Expected a CSS color, but got '" + css_color + "'");
}
}
static bool parse_from_string(color & c, std::string const& css_color, static bool parse_from_string(color & c, std::string const& css_color,
mapnik::css_color_grammar<std::string::const_iterator> const& g) mapnik::css_color_grammar<std::string::const_iterator> const& g);
{
std::string::const_iterator first = css_color.begin();
std::string::const_iterator last = css_color.end();
bool result =
boost::spirit::qi::phrase_parse(first,
last,
g,
boost::spirit::ascii::space,
c);
return result && (first == last);
}
static color from_string(std::string const& css_color) static color from_string(std::string const& css_color);
{
color c;
init_from_string(c,css_color);
return c;
}
}; };
} }
#else
#include <mapnik/css_color_grammar_deprecated.hpp>
namespace mapnik {
class MAPNIK_DECL color_factory : boost::noncopyable
{
public:
static bool parse_from_string(color & c, std::string const& css_color,
mapnik::css_color_grammar<std::string::const_iterator> const& g)
{
std::string::const_iterator first = css_color.begin();
std::string::const_iterator last = css_color.end();
mapnik::css css_;
bool result =
boost::spirit::qi::phrase_parse(first,
last,
g,
boost::spirit::ascii::space,
css_);
if (result && (first == last))
{
c.set_red(css_.r);
c.set_green(css_.g);
c.set_blue(css_.b);
c.set_alpha(css_.a);
return true;
}
return false;
}
static void init_from_string(color & c, std::string const& css_color)
{
typedef std::string::const_iterator iterator_type;
typedef mapnik::css_color_grammar<iterator_type> css_color_grammar;
css_color_grammar g;
iterator_type first = css_color.begin();
iterator_type last = css_color.end();
mapnik::css css_;
bool result =
boost::spirit::qi::phrase_parse(first,
last,
g,
boost::spirit::ascii::space,
css_);
if (!result)
{
throw config_error(std::string("Failed to parse color value: ") +
"Expected a CSS color, but got '" + css_color + "'");
}
c.set_red(css_.r);
c.set_green(css_.g);
c.set_blue(css_.b);
c.set_alpha(css_.a);
}
static color from_string(std::string const& css_color)
{
color c;
init_from_string(c,css_color);
return c;
}
};
}
#endif
#endif // MAPNIK_COLOR_FACTORY_HPP #endif // MAPNIK_COLOR_FACTORY_HPP

View file

@ -28,31 +28,28 @@
namespace mapnik { namespace mapnik {
class xml_node;
class config_error : public std::exception class config_error : public std::exception
{ {
public: public:
config_error(): config_error(std::string const& what);
what_() {} config_error(std::string const& what, xml_node const& node);
config_error(std::string const& what, unsigned line_number, std::string const& filename);
config_error( std::string const& what ) :
what_( what )
{
}
virtual ~config_error() throw() {} virtual ~config_error() throw() {}
virtual const char * what() const throw() virtual const char * what() const throw();
{
return what_.c_str();
}
void append_context(std::string const& ctx) const
{
what_ += " " + ctx;
}
void append_context(const std::string & ctx) const;
void append_context(const std::string & ctx, xml_node const& node) const;
void append_context(xml_node const& node) const;
protected: protected:
mutable std::string what_; mutable std::string what_;
mutable unsigned line_number_;
mutable std::string file_;
mutable std::string node_name_;
mutable std::string msg_;
}; };
} }
#endif // MAPNIK_CONFIG_ERROR_HPP #endif // MAPNIK_CONFIG_ERROR_HPP

View file

@ -26,7 +26,6 @@
// mapnik // mapnik
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/expression_node.hpp> #include <mapnik/expression_node.hpp>
#include <mapnik/expression_grammar.hpp>
// stl // stl
#include <string> #include <string>
@ -35,6 +34,7 @@ namespace mapnik
{ {
typedef boost::shared_ptr<expr_node> expression_ptr; typedef boost::shared_ptr<expr_node> expression_ptr;
template <typename Iterator> struct expression_grammar;
class expression_factory class expression_factory
{ {

View file

@ -36,6 +36,7 @@ namespace mapnik {
typedef std::set<expression_ptr> expression_set; typedef std::set<expression_ptr> expression_set;
class processed_text; class processed_text;
class xml_node;
struct char_properties; struct char_properties;
namespace formatting { namespace formatting {
@ -48,7 +49,7 @@ class node
public: public:
virtual ~node() {} virtual ~node() {}
virtual void to_xml(boost::property_tree::ptree &xml) const; virtual void to_xml(boost::property_tree::ptree &xml) const;
static node_ptr from_xml(boost::property_tree::ptree const& xml); static node_ptr from_xml(xml_node const& xml);
virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const = 0; virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const = 0;
virtual void add_expressions(expression_set &output) const; virtual void add_expressions(expression_set &output) const;
}; };

View file

@ -31,7 +31,7 @@ namespace formatting {
class expression_format: public node { class expression_format: public node {
public: public:
void to_xml(boost::property_tree::ptree &xml) const; void to_xml(boost::property_tree::ptree &xml) const;
static node_ptr from_xml(boost::property_tree::ptree const& xml); static node_ptr from_xml(xml_node const& xml);
virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const; virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const;
virtual void add_expressions(expression_set &output) const; virtual void add_expressions(expression_set &output) const;
@ -51,7 +51,7 @@ public:
private: private:
node_ptr child_; node_ptr child_;
static expression_ptr get_expression(boost::property_tree::ptree const& xml, std::string name); static expression_ptr get_expression(xml_node const& xml, std::string name);
}; };
} //ns formatting } //ns formatting
} //ns mapnik } //ns mapnik

View file

@ -31,7 +31,7 @@ namespace formatting {
class format_node: public node { class format_node: public node {
public: public:
void to_xml(boost::property_tree::ptree &xml) const; void to_xml(boost::property_tree::ptree &xml) const;
static node_ptr from_xml(boost::property_tree::ptree const& xml); static node_ptr from_xml(xml_node const& xml);
virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const; virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const;
virtual void add_expressions(expression_set &output) const; virtual void add_expressions(expression_set &output) const;

View file

@ -38,7 +38,7 @@ namespace mapnik
namespace formatting namespace formatting
{ {
typedef node_ptr (*from_xml_function_ptr)(boost::property_tree::ptree const& xml); typedef node_ptr (*from_xml_function_ptr)(xml_node const& xml);
class registry : public singleton<registry, CreateStatic>, class registry : public singleton<registry, CreateStatic>,
private boost::noncopyable private boost::noncopyable
@ -47,7 +47,7 @@ public:
registry(); registry();
~registry() {} ~registry() {}
void register_name(std::string name, from_xml_function_ptr ptr, bool overwrite=false); void register_name(std::string name, from_xml_function_ptr ptr, bool overwrite=false);
node_ptr from_xml(std::string name, boost::property_tree::ptree const& xml); node_ptr from_xml(xml_node const& xml);
private: private:
std::map<std::string, from_xml_function_ptr> map_; std::map<std::string, from_xml_function_ptr> map_;
}; };

View file

@ -31,7 +31,7 @@ public:
text_node(expression_ptr text): node(), text_(text) {} text_node(expression_ptr text): node(), text_(text) {}
text_node(std::string text): node(), text_(parse_expression(text)) {} text_node(std::string text): node(), text_(parse_expression(text)) {}
void to_xml(boost::property_tree::ptree &xml) const; void to_xml(boost::property_tree::ptree &xml) const;
static node_ptr from_xml(boost::property_tree::ptree const& xml); static node_ptr from_xml(xml_node const& xml);
virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const; virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const;
virtual void add_expressions(expression_set &output) const; virtual void add_expressions(expression_set &output) const;

View file

@ -1,26 +1,34 @@
#ifndef DUMP_XML_HPP #ifndef DUMP_XML_HPP
#define DUMP_XML_HPP #define DUMP_XML_HPP
#include <boost/property_tree/ptree.hpp> #include <mapnik/xml_node.hpp>
/* Debug dump ptree XML representation. /* Debug dump ptree XML representation.
*/ */
void dump_xml(boost::property_tree::ptree const& xml, unsigned level=0) void dump_xml(xml_node const& xml, unsigned level=0)
{ {
std::string indent; std::string indent;
int i; unsigned i;
for (i=0; i<level; i++) for (i=0; i<level; i++)
{ {
indent += " "; indent += " ";
} }
if (xml.data().length()) std::cout << indent << "data: '" << xml.data() << "'\n"; xml_node::attribute_map const& attr = xml.get_attributes();
boost::property_tree::ptree::const_iterator itr = xml.begin(); std::cerr << indent <<"[" << xml.name();
boost::property_tree::ptree::const_iterator end = xml.end(); xml_node::attribute_map::const_iterator aitr = attr.begin();
xml_node::attribute_map::const_iterator aend = attr.end();
for (;aitr!=aend; aitr++)
{
std::cerr << " (" << aitr->first << ", " << aitr->second.value << ", " << aitr->second.processed << ")";
}
std::cerr << "]" << "\n";
if (xml.is_text()) std::cerr << indent << "text: '" << xml.text() << "'\n";
xml_node::const_iterator itr = xml.begin();
xml_node::const_iterator end = xml.end();
for (; itr!=end; itr++) for (; itr!=end; itr++)
{ {
std::cout << indent <<"[" << itr->first << "]" << "\n"; dump_xml(*itr, level+1);
dump_xml(itr->second, level+1);
std::cout << indent << "[/" << itr->first << "]" << "\n";
} }
std::cerr << indent << "[/" << xml.name() << "]" << "\n";
} }

View file

@ -30,6 +30,7 @@
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
namespace mapnik { namespace mapnik {
class xml_node;
/** /**
* Creates a metawriter with the properties specified in the property * Creates a metawriter with the properties specified in the property
@ -37,7 +38,7 @@ namespace mapnik {
* metawriters, but should provide an easy point to make them a * metawriters, but should provide an easy point to make them a
* proper factory method if this is wanted in the future. * proper factory method if this is wanted in the future.
*/ */
metawriter_ptr metawriter_create(const boost::property_tree::ptree &pt); metawriter_ptr metawriter_create(xml_node const& pt);
/** /**
* Writes properties into the given property tree representing the * Writes properties into the given property tree representing the

View file

@ -26,7 +26,6 @@
// mapnik // mapnik
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/global.hpp> #include <mapnik/global.hpp>
#include <mapnik/config_error.hpp>
// boost // boost
#include <boost/utility.hpp> #include <boost/utility.hpp>

View file

@ -23,450 +23,17 @@
#ifndef MAPNIK_PTREE_HELPERS_HPP #ifndef MAPNIK_PTREE_HELPERS_HPP
#define MAPNIK_PTREE_HELPERS_HPP #define MAPNIK_PTREE_HELPERS_HPP
// mapnik
#include <mapnik/enumeration.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/util/conversions.hpp>
// boost // boost
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/optional.hpp>
#include <boost/lexical_cast.hpp>
// stl
#include <iostream>
#include <sstream>
namespace mapnik { namespace mapnik {
template <typename T>
inline boost::optional<T> fast_cast(std::string const& value);
template <typename T>
T get(boost::property_tree::ptree const& node, std::string const& name, bool is_attribute,
T const& default_value);
template <typename T>
T get(boost::property_tree::ptree const& node, std::string const& name, bool is_attribute);
template <typename T>
T get_value(boost::property_tree::ptree const& node, std::string const& name);
template <typename T>
boost::optional<T> get_optional(boost::property_tree::ptree const& node, std::string const& name,
bool is_attribute);
template <typename T>
boost::optional<T> get_opt_attr( boost::property_tree::ptree const& node,
std::string const& name)
{
return get_optional<T>( node, name, true);
}
template <typename T>
boost::optional<T> get_opt_child( boost::property_tree::ptree const& node,
std::string const& name)
{
return get_optional<T>( node, name, false);
}
template <typename T>
T get_attr( boost::property_tree::ptree const& node, std::string const& name,
T const& default_value )
{
return get<T>( node, name, true, default_value);
}
template <typename T>
T get_attr( boost::property_tree::ptree const& node, std::string const& name )
{
return get<T>( node, name, true );
}
template <typename charT, typename traits>
std::basic_ostream<charT, traits> &
operator << ( std::basic_ostream<charT, traits> & s, mapnik::color const& c )
{
std::string hex_string( c.to_string() );
s << hex_string;
return s;
}
/** Helper for class bool */
class boolean {
public:
boolean() : b_(false) {}
boolean(bool b) : b_(b) {}
boolean(boolean const& b) : b_(b.b_) {}
operator bool() const
{
return b_;
}
boolean & operator = (boolean const& other)
{
b_ = other.b_;
return * this;
}
boolean & operator = (bool other)
{
b_ = other;
return * this;
}
private:
bool b_;
};
/** Special stream input operator for boolean values */
template <typename charT, typename traits>
std::basic_istream<charT, traits> &
operator >> ( std::basic_istream<charT, traits> & s, boolean & b )
{
std::string word;
s >> word;
if ( s )
{
if ( word == "true" || word == "yes" || word == "on" ||
word == "1")
{
b = true;
}
else if ( word == "false" || word == "no" || word == "off" ||
word == "0")
{
b = false;
}
else
{
s.setstate( std::ios::failbit );
}
}
return s;
}
template <typename charT, typename traits>
std::basic_ostream<charT, traits> &
operator << ( std::basic_ostream<charT, traits> & s, boolean const& b )
{
s << ( b ? "true" : "false" );
return s;
}
template <typename T> template <typename T>
void set_attr(boost::property_tree::ptree & pt, std::string const& name, T const& v) void set_attr(boost::property_tree::ptree & pt, std::string const& name, T const& v)
{ {
pt.put("<xmlattr>." + name, v); pt.put("<xmlattr>." + name, v);
} }
class boolean;
template <typename T>
struct name_trait
{
static std::string name()
{
return "<unknown>";
}
// missing name_trait for type ...
// if you get here you are probably using a new type
// in the XML file. Just add a name trait for the new
// type below.
BOOST_STATIC_ASSERT( sizeof(T) == 0 );
};
#define DEFINE_NAME_TRAIT( type, type_name ) \
template <> \
struct name_trait<type> \
{ \
static std::string name() { return std::string("type ") + type_name; } \
};
DEFINE_NAME_TRAIT( double, "double")
DEFINE_NAME_TRAIT( float, "float")
DEFINE_NAME_TRAIT( unsigned, "unsigned")
DEFINE_NAME_TRAIT( boolean, "boolean")
DEFINE_NAME_TRAIT( int, "integer" )
DEFINE_NAME_TRAIT( std::string, "string" )
DEFINE_NAME_TRAIT( color, "color" )
template <typename ENUM, int MAX>
struct name_trait< mapnik::enumeration<ENUM, MAX> >
{
typedef enumeration<ENUM, MAX> Enum;
static std::string name()
{
std::string value_list("one of [");
for (unsigned i = 0; i < Enum::MAX; ++i)
{
value_list += Enum::get_string( i );
if ( i + 1 < Enum::MAX ) value_list += ", ";
}
value_list += "]";
return value_list;
}
};
template <typename T>
inline boost::optional<T> fast_cast(std::string const& value)
{
try
{
return boost::lexical_cast<T>( value );
}
catch (boost::bad_lexical_cast const& ex)
{
return boost::optional<T>();
}
}
template <>
inline boost::optional<int> fast_cast(std::string const& value)
{
int result;
if (mapnik::conversions::string2int(value,result))
return boost::optional<int>(result);
return boost::optional<int>();
}
template <>
inline boost::optional<double> fast_cast(std::string const& value)
{
double result;
if (mapnik::conversions::string2double(value,result))
return boost::optional<double>(result);
return boost::optional<double>();
}
template <>
inline boost::optional<float> fast_cast(std::string const& value)
{
float result;
if (mapnik::conversions::string2float(value,result))
return boost::optional<float>(result);
return boost::optional<float>();
}
template <typename T>
T get(boost::property_tree::ptree const& node,
std::string const& name,
bool is_attribute,
T const& default_value)
{
boost::optional<std::string> str;
if (is_attribute)
{
str = node.get_optional<std::string>( std::string("<xmlattr>.") + name );
}
else
{
str = node.get_optional<std::string>(name + ".<xmltext>");
}
if ( str )
{
boost::optional<T> result = fast_cast<T>(*str);
if (result)
{
return *result;
}
else
{
throw config_error(std::string("Failed to parse ") +
(is_attribute ? "attribute" : "child node") + " '" +
name + "'. Expected " + name_trait<T>::name() +
" but got '" + *str + "'");
}
}
else
{
return default_value;
}
}
template <>
inline color get(boost::property_tree::ptree const& node,
std::string const& name,
bool is_attribute,
color const& default_value)
{
boost::optional<std::string> str;
if (is_attribute)
{
str = node.get_optional<std::string>( std::string("<xmlattr>.") + name );
}
else
{
str = node.get_optional<std::string>(name + ".<xmltext>");
}
if ( str )
{
try
{
return mapnik::color_factory::from_string((*str).c_str());
}
catch (...)
{
throw config_error(std::string("Failed to parse ") +
(is_attribute ? "attribute" : "child node") + " '" +
name + "'. Expected " + name_trait<color>::name() +
" but got '" + *str + "'");
}
}
else
{
return default_value;
}
}
template <typename T>
T get(boost::property_tree::ptree const& node, std::string const& name, bool is_attribute)
{
boost::optional<std::string> str;
if (is_attribute)
{
str = node.get_optional<std::string>( std::string("<xmlattr>.") + name);
}
else
{
str = node.get_optional<std::string>(name + ".<xmltext>");
}
if ( ! str )
{
throw config_error(std::string("Required ") +
(is_attribute ? "attribute " : "child node ") +
"'" + name + "' is missing");
}
boost::optional<T> result = fast_cast<T>(*str);
if (result)
{
return *result;
}
else
{
throw config_error(std::string("Failed to parse ") +
(is_attribute ? "attribute" : "child node") + " '" +
name + "'. Expected " + name_trait<T>::name() +
" but got '" + *str + "'");
}
}
template <typename T>
T get_value(boost::property_tree::ptree const& node, std::string const& name)
{
try
{
/* NOTE: get_child works as long as there is only one child with that name.
If this function is used this used this condition must always be satisfied.
*/
return node.get_child("<xmltext>").get_value<T>();
}
catch (boost::property_tree::ptree_bad_path)
{
/* If the XML parser did not find any non-empty data element the is no
<xmltext> node. But we don't want to fail here but simply return a
default constructed value of the requested type.
*/
return T();
}
catch (...)
{
throw config_error(std::string("Failed to parse ") +
name + ". Expected " + name_trait<T>::name() +
" but got '" + node.data() + "'");
}
}
template <typename T>
boost::optional<T> get_optional(boost::property_tree::ptree const& node,
std::string const& name,
bool is_attribute)
{
boost::optional<std::string> str;
if (is_attribute)
{
str = node.get_optional<std::string>( std::string("<xmlattr>.") + name);
}
else
{
str = node.get_optional<std::string>(name + ".<xmltext>");
}
boost::optional<T> result;
if ( str )
{
result = fast_cast<T>(*str);
if (!result)
{
throw config_error(std::string("Failed to parse ") +
(is_attribute ? "attribute" : "child node") + " '" +
name + "'. Expected " + name_trait<T>::name() +
" but got '" + *str + "'");
}
}
return result;
}
template <>
inline boost::optional<std::string> get_optional(boost::property_tree::ptree const& node,
std::string const& name,
bool is_attribute)
{
if (is_attribute)
{
return node.get_optional<std::string>( std::string("<xmlattr>.") + name);
}
else
{
return node.get_optional<std::string>(name + ".<xmltext>");
}
}
template <>
inline boost::optional<color> get_optional(boost::property_tree::ptree const& node,
std::string const& name,
bool is_attribute)
{
boost::optional<std::string> str;
if (is_attribute)
{
str = node.get_optional<std::string>( std::string("<xmlattr>.") + name);
}
else
{
str = node.get_optional<std::string>(name + ".<xmltext>");
}
boost::optional<color> result;
if ( str )
{
try
{
result = mapnik::color_factory::from_string((*str).c_str());
}
catch (...)
{
throw config_error(std::string("Failed to parse ") +
(is_attribute ? "attribute" : "child node") + " '" +
name + "'. Expected " + name_trait<color>::name() +
" but got '" + *str + "'");
}
}
return result;
}
static inline bool has_child(boost::property_tree::ptree const& node, std::string const& name)
{
boost::optional<std::string> str = node.get_optional<std::string>(name);
return str;
}
} // end of namespace mapnik } // end of namespace mapnik
#endif // MAPNIK_PTREE_HELPERS_HPP #endif // MAPNIK_PTREE_HELPERS_HPP

View file

@ -39,7 +39,6 @@
// mapnik // mapnik
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/color.hpp> #include <mapnik/color.hpp>
#include <mapnik/feature.hpp> #include <mapnik/feature.hpp>
#include <mapnik/enumeration.hpp> #include <mapnik/enumeration.hpp>

View file

@ -65,11 +65,11 @@ public:
detector_(detector), detector_(detector),
writer_(sym.get_metawriter()), writer_(sym.get_metawriter()),
dims_(0, 0, width, height), dims_(0, 0, width, height),
query_extent_(query_extent),
text_(font_manager, scale_factor), text_(font_manager, scale_factor),
angle_(0.0), angle_(0.0),
placement_valid_(false), placement_valid_(false),
points_on_line_(false), points_on_line_(false),
query_extent_(query_extent),
finder_() finder_()
{ {
initialize_geometries(); initialize_geometries();

View file

@ -38,7 +38,7 @@ public:
text_symbolizer_properties & add(); text_symbolizer_properties & add();
text_symbolizer_properties & get(unsigned i); text_symbolizer_properties & get(unsigned i);
unsigned size() const; unsigned size() const;
static text_placements_ptr from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets); static text_placements_ptr from_xml(xml_node const &xml, fontset_map const & fontsets);
private: private:
std::vector<text_symbolizer_properties> list_; std::vector<text_symbolizer_properties> list_;
friend class text_placement_info_list; friend class text_placement_info_list;

View file

@ -39,7 +39,7 @@ namespace placements
{ {
typedef text_placements_ptr (*from_xml_function_ptr)( typedef text_placements_ptr (*from_xml_function_ptr)(
boost::property_tree::ptree const& xml, fontset_map const & fontsets); xml_node const& xml, fontset_map const & fontsets);
class registry : public singleton<registry, CreateStatic>, class registry : public singleton<registry, CreateStatic>,
private boost::noncopyable private boost::noncopyable
@ -49,7 +49,7 @@ public:
~registry() {} ~registry() {}
void register_name(std::string name, from_xml_function_ptr ptr, bool overwrite=false); void register_name(std::string name, from_xml_function_ptr ptr, bool overwrite=false);
text_placements_ptr from_xml(std::string name, text_placements_ptr from_xml(std::string name,
boost::property_tree::ptree const& xml, xml_node const& xml,
fontset_map const & fontsets); fontset_map const & fontsets);
private: private:
std::map<std::string, from_xml_function_ptr> map_; std::map<std::string, from_xml_function_ptr> map_;

View file

@ -52,7 +52,7 @@ public:
text_placement_info_ptr get_placement_info(double scale_factor) const; text_placement_info_ptr get_placement_info(double scale_factor) const;
void set_positions(std::string positions); void set_positions(std::string positions);
std::string get_positions(); std::string get_positions();
static text_placements_ptr from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets); static text_placements_ptr from_xml(xml_node const &xml, fontset_map const & fontsets);
private: private:
std::string positions_; std::string positions_;
std::vector<directions_t> direction_; std::vector<directions_t> direction_;

View file

@ -54,7 +54,7 @@ struct char_properties
{ {
char_properties(); char_properties();
/** Construct object from XML. */ /** Construct object from XML. */
void from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets); void from_xml(xml_node const &sym, fontset_map const & fontsets);
/** Write object to XML ptree. */ /** Write object to XML ptree. */
void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, char_properties const& dfl=char_properties()) const; void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, char_properties const& dfl=char_properties()) const;
std::string face_name; std::string face_name;
@ -124,7 +124,7 @@ struct text_symbolizer_properties
{ {
text_symbolizer_properties(); text_symbolizer_properties();
/** Load all values from XML ptree. */ /** Load all values from XML ptree. */
void from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets); void from_xml(xml_node const &sym, fontset_map const & fontsets);
/** Save all values to XML ptree (but does not create a new parent node!). */ /** Save all values to XML ptree (but does not create a new parent node!). */
void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_symbolizer_properties const &dfl=text_symbolizer_properties()) const; void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_symbolizer_properties const &dfl=text_symbolizer_properties()) const;

View file

@ -30,16 +30,16 @@
namespace mapnik { namespace conversions { namespace mapnik { namespace conversions {
bool string2int(const char * value, int & result); bool string2int(const char * value, int & result);
bool string2int(std::string const& value, int & result); bool string2int(std::string const& value, int & result);
bool string2double(std::string const& value, double & result); bool string2double(std::string const& value, double & result);
bool string2double(const char * value, double & result); bool string2double(const char * value, double & result);
bool string2float(std::string const& value, float & result); bool string2float(std::string const& value, float & result);
bool string2float(const char * value, float & result); bool string2float(const char * value, float & result);
} }
} }
#endif // MAPNIK_CONVERSIONS_UTIL_HPP #endif // MAPNIK_CONVERSIONS_UTIL_HPP

View file

@ -26,7 +26,6 @@
// mapnik // mapnik
#include <mapnik/global.hpp> #include <mapnik/global.hpp>
#include <mapnik/unicode.hpp> #include <mapnik/unicode.hpp>
#include <mapnik/config_error.hpp>
// boost // boost
#include <boost/variant.hpp> #include <boost/variant.hpp>

View file

@ -23,16 +23,14 @@
#ifndef MAPNIK_LIBXML2_LOADER_HPP #ifndef MAPNIK_LIBXML2_LOADER_HPP
#define MAPNIK_LIBXML2_LOADER_HPP #define MAPNIK_LIBXML2_LOADER_HPP
// boost
#include <boost/property_tree/ptree.hpp>
// stl // stl
#include <string> #include <string>
namespace mapnik namespace mapnik
{ {
void read_xml2( std::string const & filename, boost::property_tree::ptree & pt); class xml_node;
void read_xml2_string( std::string const & str, boost::property_tree::ptree & pt, std::string const & base_path=""); void read_xml(std::string const & filename, xml_node &node);
void read_xml_string(std::string const & str, xml_node &node, std::string const & base_path="");
} }
#endif // MAPNIK_LIBXML2_LOADER_HPP #endif // MAPNIK_LIBXML2_LOADER_HPP

137
include/mapnik/xml_node.hpp Normal file
View file

@ -0,0 +1,137 @@
/*****************************************************************************
*
* 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_NODE_H
#define MAPNIK_XML_NODE_H
//mapnik
#include <mapnik/boolean.hpp>
//boost
#include <boost/optional.hpp>
//stl
#include <list>
#include <string>
#include <map>
#include <exception>
namespace mapnik
{
class xml_tree;
class xml_attribute
{
public:
xml_attribute(std::string const& value);
std::string value;
mutable bool processed;
};
class node_not_found: public std::exception
{
public:
node_not_found(std::string node_name);
virtual const char* what() const throw();
~node_not_found() throw ();
private:
std::string node_name_;
};
class attribute_not_found: public std::exception
{
public:
attribute_not_found(std::string const& node_name, std::string const& attribute_name);
virtual const char* what() const throw();
~attribute_not_found() throw ();
private:
std::string node_name_;
std::string attribute_name_;
};
class more_than_one_child: public std::exception
{
public:
more_than_one_child(std::string const& node_name);
virtual const char* what() const throw();
~more_than_one_child() throw ();
private:
std::string node_name_;
};
class xml_node
{
public:
typedef std::list<xml_node>::const_iterator const_iterator;
typedef std::map<std::string, xml_attribute> attribute_map;
xml_node(xml_tree &tree, std::string name, unsigned line=0, bool text_node = false);
std::string const& name() const;
std::string const& text() const;
std::string const& filename() const;
bool is_text() const;
bool is(std::string const& name) const;
xml_node &add_child(std::string const& name, unsigned line=0, bool text_node = false);
void add_attribute(std::string const& name, std::string const& value);
attribute_map const& get_attributes() const;
bool processed() const;
void set_processed(bool processed) const;
unsigned line() const;
const_iterator begin() const;
const_iterator end() const;
xml_node & get_child(std::string const& name);
xml_node const& get_child(std::string const& name) const;
xml_node const* get_opt_child(std::string const& name) const;
bool has_child(std::string const& name) const;
template <typename T>
boost::optional<T> get_opt_attr(std::string const& name) const;
template <typename T>
T get_attr(std::string const& name, T const& default_value) const;
template <typename T>
T get_attr(std::string const& name) const;
std::string get_text() const;
template <typename T>
T get_value() const;
private:
xml_tree &tree_;
std::string name_;
std::list<xml_node> children_;
attribute_map attributes_;
bool text_node_;
unsigned line_;
mutable bool processed_;
static std::string xml_text;
};
} //ns mapnik
#endif // MAPNIK_XML_NODE_H

View file

@ -0,0 +1,54 @@
/*****************************************************************************
*
* 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
//mapnik
#include <mapnik/xml_node.hpp>
#include <mapnik/expression_grammar.hpp>
#include <mapnik/css_color_grammar.hpp>
//stl
#include <string>
namespace mapnik
{
class xml_tree
{
public:
xml_tree(std::string const& encoding="utf8");
void set_filename(std::string fn);
std::string const& filename() const;
xml_node &root();
private:
xml_node node_;
std::string file_;
transcoder tr_;
public:
mapnik::css_color_grammar<std::string::const_iterator> color_grammar;
mapnik::expression_grammar<std::string::const_iterator> expr_grammar;
};
} //ns mapnik
#endif // MAPNIK_XML_TREE_H

View file

@ -6,6 +6,7 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
// mapnik // mapnik
#include <mapnik/feature_layer_desc.hpp> #include <mapnik/feature_layer_desc.hpp>
@ -14,7 +15,7 @@
#include <mapnik/memory_featureset.hpp> #include <mapnik/memory_featureset.hpp>
#include <mapnik/wkt/wkt_factory.hpp> #include <mapnik/wkt/wkt_factory.hpp>
#include <mapnik/util/geometry_to_ds_type.hpp> #include <mapnik/util/geometry_to_ds_type.hpp>
#include <mapnik/ptree_helpers.hpp> // mapnik::boolean #include <mapnik/boolean.hpp>
// stl // stl
#include <sstream> #include <sstream>

View file

@ -25,7 +25,7 @@
#include "gdal_featureset.hpp" #include "gdal_featureset.hpp"
// mapnik // mapnik
#include <mapnik/ptree_helpers.hpp> #include <mapnik/boolean.hpp>
#include <mapnik/geom_util.hpp> #include <mapnik/geom_util.hpp>
#include <gdal_version.h> #include <gdal_version.h>

View file

@ -30,7 +30,7 @@
#include <cstdarg> #include <cstdarg>
// mapnik // mapnik
#include <mapnik/ptree_helpers.hpp> #include <mapnik/boolean.hpp>
#include <mapnik/geom_util.hpp> #include <mapnik/geom_util.hpp>
// boost // boost

View file

@ -33,7 +33,7 @@
#include <cstdio> #include <cstdio>
// mapnik // mapnik
#include <mapnik/ptree_helpers.hpp> #include <mapnik/boolean.hpp>
// boost // boost
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>

View file

@ -25,7 +25,7 @@
#include "occi_featureset.hpp" #include "occi_featureset.hpp"
// mapnik // mapnik
#include <mapnik/ptree_helpers.hpp> #include <mapnik/boolean.hpp>
#include <mapnik/sql_utils.hpp> #include <mapnik/sql_utils.hpp>
// boost // boost

View file

@ -33,7 +33,7 @@
#include <gdal_version.h> #include <gdal_version.h>
// mapnik // mapnik
#include <mapnik/ptree_helpers.hpp> #include <mapnik/boolean.hpp>
#include <mapnik/geom_util.hpp> #include <mapnik/geom_util.hpp>
// boost // boost

View file

@ -26,7 +26,7 @@
// mapnik // mapnik
#include <mapnik/global.hpp> #include <mapnik/global.hpp>
#include <mapnik/ptree_helpers.hpp> #include <mapnik/boolean.hpp>
#include <mapnik/sql_utils.hpp> #include <mapnik/sql_utils.hpp>
#include <mapnik/util/conversions.hpp> #include <mapnik/util/conversions.hpp>

View file

@ -29,7 +29,7 @@
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
// mapnik // mapnik
#include <mapnik/ptree_helpers.hpp> #include <mapnik/boolean.hpp>
#include <mapnik/geom_util.hpp> #include <mapnik/geom_util.hpp>
using mapnik::datasource; using mapnik::datasource;

View file

@ -26,7 +26,7 @@
#include "sqlite_utils.hpp" #include "sqlite_utils.hpp"
// mapnik // mapnik
#include <mapnik/ptree_helpers.hpp> #include <mapnik/boolean.hpp>
#include <mapnik/sql_utils.hpp> #include <mapnik/sql_utils.hpp>
#include <mapnik/util/geometry_to_ds_type.hpp> #include <mapnik/util/geometry_to_ds_type.hpp>
#include <mapnik/wkb.hpp> #include <mapnik/wkb.hpp>

View file

@ -27,7 +27,6 @@
#include <mapnik/marker.hpp> #include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp> #include <mapnik/marker_cache.hpp>
#include <mapnik/unicode.hpp> #include <mapnik/unicode.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/font_set.hpp> #include <mapnik/font_set.hpp>
#include <mapnik/parse_path.hpp> #include <mapnik/parse_path.hpp>
#include <mapnik/map.hpp> #include <mapnik/map.hpp>

View file

@ -178,6 +178,8 @@ source = Split(
text_placements/list.cpp text_placements/list.cpp
text_placements/simple.cpp text_placements/simple.cpp
text_properties.cpp text_properties.cpp
xml_tree.cpp
config_error.cpp
""" """
) )
@ -299,7 +301,7 @@ if env['XMLPARSER'] == 'libxml2' and env['HAS_LIBXML2']:
env2 = lib_env.Clone() env2 = lib_env.Clone()
env2.Append(CXXFLAGS = '-DHAVE_LIBXML2') env2.Append(CXXFLAGS = '-DHAVE_LIBXML2')
libmapnik_cxxflags.append('-DHAVE_LIBXML2') libmapnik_cxxflags.append('-DHAVE_LIBXML2')
fixup = ['load_map.cpp','libxml2_loader.cpp'] fixup = ['libxml2_loader.cpp']
for cpp in fixup: for cpp in fixup:
if cpp in source: if cpp in source:
source.remove(cpp) source.remove(cpp)
@ -307,6 +309,12 @@ if env['XMLPARSER'] == 'libxml2' and env['HAS_LIBXML2']:
source.insert(0,env2.StaticObject(cpp)) source.insert(0,env2.StaticObject(cpp))
else: else:
source.insert(0,env2.SharedObject(cpp)) source.insert(0,env2.SharedObject(cpp))
else:
source += Split(
"""
rapidxml_loader.cpp
"""
)
if env['CUSTOM_LDFLAGS']: if env['CUSTOM_LDFLAGS']:
linkflags = '%s %s' % (env['CUSTOM_LDFLAGS'], mapnik_lib_link_flag) linkflags = '%s %s' % (env['CUSTOM_LDFLAGS'], mapnik_lib_link_flag)

View file

@ -29,7 +29,6 @@
#include <mapnik/unicode.hpp> #include <mapnik/unicode.hpp>
#include <mapnik/markers_placement.hpp> #include <mapnik/markers_placement.hpp>
#include <mapnik/arrow.hpp> #include <mapnik/arrow.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/parse_path.hpp> #include <mapnik/parse_path.hpp>
#include <mapnik/marker.hpp> #include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp> #include <mapnik/marker_cache.hpp>

View file

@ -25,11 +25,23 @@
// mapnik // mapnik
#include <mapnik/color.hpp> #include <mapnik/color.hpp>
#include <mapnik/color_factory.hpp> #include <mapnik/color_factory.hpp>
#include <mapnik/config_error.hpp>
// boost // boost
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/version.hpp>
// stl // stl
#include <sstream> #include <sstream>
// boost 1.41 -> 1.44 compatibility, to be removed in mapnik 2.1 (dane)
#if BOOST_VERSION >= 104500
#include <mapnik/css_color_grammar.hpp>
#else
#include <mapnik/css_color_grammar_deprecated.hpp>
#endif
namespace mapnik { namespace mapnik {
color::color( std::string const& css_string) color::color( std::string const& css_string)
@ -81,5 +93,89 @@ std::string color::to_hex_string() const
} }
} }
/****************************************************************************/
void color_factory::init_from_string(color & c, std::string const& css_color)
{
typedef std::string::const_iterator iterator_type;
typedef mapnik::css_color_grammar<iterator_type> css_color_grammar;
css_color_grammar g;
iterator_type first = css_color.begin();
iterator_type last = css_color.end();
// boost 1.41 -> 1.44 compatibility, to be removed in mapnik 2.1 (dane)
#if BOOST_VERSION >= 104500
bool result =
boost::spirit::qi::phrase_parse(first,
last,
g,
boost::spirit::ascii::space,
c);
if (!result)
{
throw config_error(std::string("Failed to parse color value: ") +
"Expected a CSS color, but got '" + css_color + "'");
}
#else
mapnik::css css_;
bool result =
boost::spirit::qi::phrase_parse(first,
last,
g,
boost::spirit::ascii::space,
css_);
if (!result)
{
throw config_error(std::string("Failed to parse color value: ") +
"Expected a CSS color, but got '" + css_color + "'");
}
c.set_red(css_.r);
c.set_green(css_.g);
c.set_blue(css_.b);
c.set_alpha(css_.a);
#endif
}
bool color_factory::parse_from_string(color & c, std::string const& css_color,
mapnik::css_color_grammar<std::string::const_iterator> const& g)
{
std::string::const_iterator first = css_color.begin();
std::string::const_iterator last = css_color.end();
// boost 1.41 -> 1.44 compatibility, to be removed in mapnik 2.1 (dane)
#if BOOST_VERSION >= 104500
bool result =
boost::spirit::qi::phrase_parse(first,
last,
g,
boost::spirit::ascii::space,
c);
return result && (first == last);
#else
mapnik::css css_;
bool result =
boost::spirit::qi::phrase_parse(first,
last,
g,
boost::spirit::ascii::space,
css_);
if (result && (first == last))
{
c.set_red(css_.r);
c.set_green(css_.g);
c.set_blue(css_.b);
c.set_alpha(css_.a);
return true;
}
#endif
}
color color_factory::from_string(std::string const& css_color)
{
color c;
init_from_string(c, css_color);
return c;
}
} }

55
src/config_error.cpp Normal file
View file

@ -0,0 +1,55 @@
#include <mapnik/config_error.hpp>
#include <mapnik/xml_tree.hpp>
namespace mapnik
{
config_error::config_error(std::string const& what)
: what_(what), line_number_(0), file_(), node_name_(), msg_()
{
}
config_error::config_error(std::string const& what, xml_node const& node)
: what_(what), line_number_(node.line()), file_(node.filename()), node_name_(node.name()), msg_()
{
}
config_error::config_error(std::string const& what, unsigned line_number, std::string const& filename)
: what_(what), line_number_(line_number), file_(filename), node_name_(), msg_()
{
}
char const* config_error::what() const throw()
{
std::stringstream s;
s << file_;
if (line_number_ > 0) s << " line " << line_number_;
if (!node_name_.empty()) s << " in node "<< node_name_;
if (line_number_ > 0 || !file_.empty()) s << ": ";
s << what_;
msg_ = s.str(); //Avoid returning pointer to dead object
return msg_.c_str();
}
void config_error::append_context(std::string const& ctx) const
{
what_ += " " + ctx;
}
void config_error::append_context(std::string const& ctx, xml_node const& node) const
{
append_context(ctx);
append_context(node);
}
void config_error::append_context(xml_node const& node) const
{
if (!line_number_) line_number_ = node.line();
if (node_name_.empty()) node_name_ = node.name();
if (file_.empty()) file_ = node.filename();
}
}

View file

@ -35,9 +35,9 @@ namespace mapnik { namespace conversions {
using namespace boost::spirit; using namespace boost::spirit;
BOOST_SPIRIT_AUTO(qi, INTEGER, qi::int_); BOOST_SPIRIT_AUTO(qi, INTEGER, qi::int_)
BOOST_SPIRIT_AUTO(qi, FLOAT, qi::float_); BOOST_SPIRIT_AUTO(qi, FLOAT, qi::float_)
BOOST_SPIRIT_AUTO(qi, DOUBLE, qi::double_); BOOST_SPIRIT_AUTO(qi, DOUBLE, qi::double_)
bool string2int(const char * value, int & result) bool string2int(const char * value, int & result)
{ {

View file

@ -24,6 +24,7 @@
#include <mapnik/expression.hpp> #include <mapnik/expression.hpp>
#include <mapnik/config_error.hpp> #include <mapnik/config_error.hpp>
#include <mapnik/unicode.hpp> #include <mapnik/unicode.hpp>
#include <mapnik/expression_grammar.hpp>
// boost // boost
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>

View file

@ -23,6 +23,7 @@
#include <mapnik/formatting/base.hpp> #include <mapnik/formatting/base.hpp>
#include <mapnik/formatting/list.hpp> #include <mapnik/formatting/list.hpp>
#include <mapnik/formatting/registry.hpp> #include <mapnik/formatting/registry.hpp>
#include <mapnik/xml_node.hpp>
// boost // boost
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
@ -38,18 +39,18 @@ void node::to_xml(boost::property_tree::ptree &xml) const
#endif #endif
} }
node_ptr node::from_xml(boost::property_tree::ptree const& xml) node_ptr node::from_xml(xml_node const& xml)
{ {
list_node *list = new list_node(); list_node *list = new list_node();
node_ptr list_ptr(list); node_ptr list_ptr(list);
boost::property_tree::ptree::const_iterator itr = xml.begin(); xml_node::const_iterator itr = xml.begin();
boost::property_tree::ptree::const_iterator end = xml.end(); xml_node::const_iterator end = xml.end();
for (; itr != end; ++itr) { for (; itr != end; ++itr) {
if (itr->first == "<xmlcomment>" || itr->first == "<xmlattr>" || itr->first == "Placement") if (itr->name() == "Placement")
{ {
continue; continue;
} }
node_ptr n = registry::instance()->from_xml(itr->first, itr->second); node_ptr n = registry::instance()->from_xml(*itr);
if (n) list->push_back(n); if (n) list->push_back(n);
} }
if (list->get_children().size() == 1) { if (list->get_children().size() == 1) {

View file

@ -27,6 +27,7 @@
#include <mapnik/expression_evaluator.hpp> #include <mapnik/expression_evaluator.hpp>
#include <mapnik/text_properties.hpp> #include <mapnik/text_properties.hpp>
#include <mapnik/feature.hpp> #include <mapnik/feature.hpp>
#include <mapnik/xml_node.hpp>
// boost // boost
@ -37,7 +38,7 @@ namespace formatting
using boost::property_tree::ptree; using boost::property_tree::ptree;
void expression_format::to_xml(boost::property_tree::ptree &xml) const void expression_format::to_xml(boost::property_tree::ptree &xml) const
{ {
ptree &new_node = xml.push_back(ptree::value_type("Format", ptree()))->second; ptree &new_node = xml.push_back(ptree::value_type("ExpressionFormat", ptree()))->second;
if (face_name) set_attr(new_node, "face-name", to_expression_string(*face_name)); if (face_name) set_attr(new_node, "face-name", to_expression_string(*face_name));
if (text_size) set_attr(new_node, "size", to_expression_string(*text_size)); if (text_size) set_attr(new_node, "size", to_expression_string(*text_size));
if (character_spacing) set_attr(new_node, "character-spacing", to_expression_string*character_spacing); if (character_spacing) set_attr(new_node, "character-spacing", to_expression_string*character_spacing);
@ -51,7 +52,7 @@ void expression_format::to_xml(boost::property_tree::ptree &xml) const
if (child_) child_->to_xml(new_node); if (child_) child_->to_xml(new_node);
} }
node_ptr expression_format::from_xml(ptree const& xml) node_ptr expression_format::from_xml(xml_node const& xml)
{ {
expression_format *n = new expression_format(); expression_format *n = new expression_format();
node_ptr np(n); node_ptr np(n);
@ -72,9 +73,9 @@ node_ptr expression_format::from_xml(ptree const& xml)
return np; return np;
} }
expression_ptr expression_format::get_expression(ptree const& xml, std::string name) expression_ptr expression_format::get_expression(xml_node const& xml, std::string name)
{ {
boost::optional<std::string> tmp = get_opt_attr<std::string>(xml, name); boost::optional<std::string> tmp = xml.get_opt_attr<std::string>(name);
if (tmp) return parse_expression(*tmp); if (tmp) return parse_expression(*tmp);
return expression_ptr(); return expression_ptr();
} }

View file

@ -21,6 +21,7 @@
*****************************************************************************/ *****************************************************************************/
#include <mapnik/formatting/format.hpp> #include <mapnik/formatting/format.hpp>
#include <mapnik/ptree_helpers.hpp> #include <mapnik/ptree_helpers.hpp>
#include <mapnik/xml_node.hpp>
namespace mapnik { namespace mapnik {
using boost::property_tree::ptree; using boost::property_tree::ptree;
@ -44,7 +45,7 @@ void format_node::to_xml(ptree &xml) const
} }
node_ptr format_node::from_xml(ptree const& xml) node_ptr format_node::from_xml(xml_node const& xml)
{ {
format_node *n = new format_node(); format_node *n = new format_node();
node_ptr np(n); node_ptr np(n);
@ -52,19 +53,19 @@ node_ptr format_node::from_xml(ptree const& xml)
node_ptr child = node::from_xml(xml); node_ptr child = node::from_xml(xml);
n->set_child(child); n->set_child(child);
n->face_name = get_opt_attr<std::string>(xml, "face-name"); n->face_name = xml.get_opt_attr<std::string>("face-name");
/*TODO: Fontset is problematic. We don't have the fontsets pointer here... */ /*TODO: Fontset is problematic. We don't have the fontsets pointer here... */
n->text_size = get_opt_attr<unsigned>(xml, "size"); n->text_size = xml.get_opt_attr<unsigned>("size");
n->character_spacing = get_opt_attr<unsigned>(xml, "character-spacing"); n->character_spacing = xml.get_opt_attr<unsigned>("character-spacing");
n->line_spacing = get_opt_attr<unsigned>(xml, "line-spacing"); n->line_spacing = xml.get_opt_attr<unsigned>("line-spacing");
n->text_opacity = get_opt_attr<double>(xml, "opactity"); n->text_opacity = xml.get_opt_attr<double>("opactity");
boost::optional<boolean> wrap = get_opt_attr<boolean>(xml, "wrap-before"); boost::optional<boolean> wrap = xml.get_opt_attr<boolean>("wrap-before");
if (wrap) n->wrap_before = *wrap; if (wrap) n->wrap_before = *wrap;
n->wrap_char = get_opt_attr<unsigned>(xml, "wrap-character"); n->wrap_char = xml.get_opt_attr<unsigned>("wrap-character");
n->text_transform = get_opt_attr<text_transform_e>(xml, "text-transform"); n->text_transform = xml.get_opt_attr<text_transform_e>("text-transform");
n->fill = get_opt_attr<color>(xml, "fill"); n->fill = xml.get_opt_attr<color>("fill");
n->halo_fill = get_opt_attr<color>(xml, "halo-fill"); n->halo_fill = xml.get_opt_attr<color>("halo-fill");
n->halo_radius = get_opt_attr<double>(xml, "halo-radius"); n->halo_radius = xml.get_opt_attr<double>("halo-radius");
return np; return np;
} }

View file

@ -24,6 +24,8 @@
#include <mapnik/formatting/text.hpp> #include <mapnik/formatting/text.hpp>
#include <mapnik/formatting/format.hpp> #include <mapnik/formatting/format.hpp>
#include <mapnik/formatting/expression.hpp> #include <mapnik/formatting/expression.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/config_error.hpp>
namespace mapnik namespace mapnik
{ {
@ -46,10 +48,11 @@ void registry::register_name(std::string name, from_xml_function_ptr ptr, bool o
} }
} }
node_ptr registry::from_xml(std::string name, const boost::property_tree::ptree &xml) node_ptr registry::from_xml(xml_node const& xml)
{ {
std::map<std::string, from_xml_function_ptr>::const_iterator itr = map_.find(name); std::map<std::string, from_xml_function_ptr>::const_iterator itr = map_.find(xml.name());
if (itr == map_.end()) throw config_error("Unknown element '" + name + "'"); if (itr == map_.end()) throw config_error("Unknown element '" + xml.name() + "'", xml);
xml.set_processed(true);
return itr->second(xml); return itr->second(xml);
} }
} //ns formatting } //ns formatting

View file

@ -26,10 +26,7 @@
#include <mapnik/feature.hpp> #include <mapnik/feature.hpp>
#include <mapnik/text_properties.hpp> #include <mapnik/text_properties.hpp>
#include <mapnik/processed_text.hpp> #include <mapnik/processed_text.hpp>
#include <mapnik/xml_node.hpp>
// boost
#include <boost/algorithm/string.hpp>
#include <boost/make_shared.hpp>
namespace mapnik namespace mapnik
{ {
@ -46,10 +43,9 @@ void text_node::to_xml(ptree &xml) const
} }
node_ptr text_node::from_xml(boost::property_tree::ptree const& xml) node_ptr text_node::from_xml(xml_node const& xml)
{ {
std::string data = xml.data(); std::string data = xml.text();
boost::trim(data);
if (data.empty()) return node_ptr(); //No text if (data.empty()) return node_ptr(); //No text
return boost::make_shared<text_node>(parse_expression(data, "utf8")); return boost::make_shared<text_node>(parse_expression(data, "utf8"));
} }

View file

@ -32,7 +32,6 @@
#include <mapnik/marker.hpp> #include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp> #include <mapnik/marker_cache.hpp>
#include <mapnik/unicode.hpp> #include <mapnik/unicode.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/font_set.hpp> #include <mapnik/font_set.hpp>
#include <mapnik/parse_path.hpp> #include <mapnik/parse_path.hpp>
#include <mapnik/map.hpp> #include <mapnik/map.hpp>

View file

@ -33,17 +33,17 @@ namespace mapnik { namespace json {
#if BOOST_VERSION >= 104700 #if BOOST_VERSION >= 104700
template <typename Iterator> template <typename Iterator>
feature_collection_parser<Iterator>::feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr) feature_collection_parser<Iterator>::feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr)
: grammar_(new feature_collection_grammar<iterator_type,feature_type>(ctx,tr)) {} : grammar_(new feature_collection_grammar<iterator_type,feature_type>(ctx,tr)) {}
template <typename Iterator> template <typename Iterator>
feature_collection_parser<Iterator>::~feature_collection_parser() {} feature_collection_parser<Iterator>::~feature_collection_parser() {}
#endif #endif
template <typename Iterator> template <typename Iterator>
bool feature_collection_parser<Iterator>::parse(iterator_type first, iterator_type last, std::vector<mapnik::feature_ptr> & features) bool feature_collection_parser<Iterator>::parse(iterator_type first, iterator_type last, std::vector<mapnik::feature_ptr> & features)
{ {
#if BOOST_VERSION >= 104700 #if BOOST_VERSION >= 104700
using namespace boost::spirit; using namespace boost::spirit;
return qi::phrase_parse(first, last, *grammar_, standard_wide::space, features); return qi::phrase_parse(first, last, *grammar_, standard_wide::space, features);
@ -53,9 +53,9 @@ bool feature_collection_parser<Iterator>::parse(iterator_type first, iterator_ty
throw std::runtime_error("mapnik::feature_collection_parser::parse() requires at least boost 1.47 while your build was compiled against boost " + s.str()); throw std::runtime_error("mapnik::feature_collection_parser::parse() requires at least boost 1.47 while your build was compiled against boost " + s.str());
return false; return false;
#endif #endif
} }
template class feature_collection_parser<std::string::const_iterator> ; template class feature_collection_parser<std::string::const_iterator> ;
template class feature_collection_parser<boost::spirit::multi_pass<std::istreambuf_iterator<char> > >; template class feature_collection_parser<boost::spirit::multi_pass<std::istreambuf_iterator<char> > >;
}} }}

View file

@ -32,30 +32,30 @@
namespace mapnik { namespace json { namespace mapnik { namespace json {
feature_generator::feature_generator() feature_generator::feature_generator()
: grammar_(new feature_generator_grammar<sink_type>()) {} : grammar_(new feature_generator_grammar<sink_type>()) {}
feature_generator::~feature_generator() {} feature_generator::~feature_generator() {}
bool feature_generator::generate(std::string & geojson, mapnik::Feature const& f) bool feature_generator::generate(std::string & geojson, mapnik::Feature const& f)
{ {
sink_type sink(geojson); sink_type sink(geojson);
return karma::generate(sink, *grammar_,f); return karma::generate(sink, *grammar_,f);
} }
geometry_generator::geometry_generator() geometry_generator::geometry_generator()
: grammar_(new multi_geometry_generator_grammar<sink_type>()) {} : grammar_(new multi_geometry_generator_grammar<sink_type>()) {}
geometry_generator::~geometry_generator() {} geometry_generator::~geometry_generator() {}
bool geometry_generator::generate(std::string & geojson, mapnik::geometry_container const& g) bool geometry_generator::generate(std::string & geojson, mapnik::geometry_container const& g)
{ {
sink_type sink(geojson); sink_type sink(geojson);
return karma::generate(sink, *grammar_,g); return karma::generate(sink, *grammar_,g);
} }
}} }}
#else #else
@ -65,22 +65,22 @@ bool geometry_generator::generate(std::string & geojson, mapnik::geometry_contai
namespace mapnik { namespace json { namespace mapnik { namespace json {
bool feature_generator::generate(std::string & geojson, mapnik::Feature const& f) bool feature_generator::generate(std::string & geojson, mapnik::Feature const& f)
{ {
std::ostringstream s; std::ostringstream s;
s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
throw std::runtime_error("feature_generator::generate() requires at least boost 1.47 while your build was compiled against boost " + s.str()); throw std::runtime_error("feature_generator::generate() requires at least boost 1.47 while your build was compiled against boost " + s.str());
return false; return false;
} }
bool geometry_generator::generate(std::string & geojson, mapnik::geometry_container const& g) bool geometry_generator::generate(std::string & geojson, mapnik::geometry_container const& g)
{ {
std::ostringstream s; std::ostringstream s;
s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
throw std::runtime_error("geometry_generator::generate() requires at least boost 1.47 while your build was compiled against boost " + s.str()); throw std::runtime_error("geometry_generator::generate() requires at least boost 1.47 while your build was compiled against boost " + s.str());
return false; return false;
} }
}} }}
#endif #endif

View file

@ -22,26 +22,27 @@
#ifdef HAVE_LIBXML2 #ifdef HAVE_LIBXML2
#include <mapnik/libxml2_loader.hpp> // mapnik
#include <mapnik/xml_loader.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/config_error.hpp> #include <mapnik/config_error.hpp>
// boost
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string/trim.hpp> #include <boost/algorithm/string/trim.hpp>
// libxml
#include <libxml/parser.h> #include <libxml/parser.h>
#include <libxml/tree.h> #include <libxml/tree.h>
#include <libxml/parserInternals.h> #include <libxml/parserInternals.h>
#include <libxml/xinclude.h> #include <libxml/xinclude.h>
// stl
#include <iostream> #include <iostream>
using boost::property_tree::ptree;
using namespace std; 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) #define DEFAULT_OPTIONS (XML_PARSE_NOERROR | XML_PARSE_NOENT | XML_PARSE_NOBLANKS | XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA)
namespace mapnik namespace mapnik
@ -50,14 +51,14 @@ class libxml2_loader : boost::noncopyable
{ {
public: public:
libxml2_loader(const char *encoding = NULL, int options = DEFAULT_OPTIONS, const char *url = NULL) : libxml2_loader(const char *encoding = NULL, int options = DEFAULT_OPTIONS, const char *url = NULL) :
ctx_( 0 ), ctx_(0),
encoding_( encoding ), encoding_(encoding),
options_( options ), options_(options),
url_( url ) url_(url)
{ {
LIBXML_TEST_VERSION; LIBXML_TEST_VERSION;
ctx_ = xmlNewParserCtxt(); ctx_ = xmlNewParserCtxt();
if ( ! ctx_ ) if (!ctx_)
{ {
throw std::runtime_error("Failed to create parser context."); throw std::runtime_error("Failed to create parser context.");
} }
@ -71,19 +72,19 @@ public:
} }
} }
void load( std::string const& filename, ptree & pt ) void load(std::string const& filename, xml_node &node)
{ {
boost::filesystem::path path(filename); 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"); throw config_error(string("Could not load map file: File does not exist"), 0, filename);
} }
xmlDocPtr doc = xmlCtxtReadFile(ctx_, filename.c_str(), encoding_, options_); xmlDocPtr doc = xmlCtxtReadFile(ctx_, filename.c_str(), encoding_, options_);
if ( !doc ) if (!doc)
{ {
xmlError * error = xmlCtxtGetLastError( ctx_ ); xmlError * error = xmlCtxtGetLastError(ctx_);
if (error) if (error)
{ {
std::ostringstream os; std::ostringstream os;
@ -91,15 +92,7 @@ public:
os << ": " << std::endl << error->message; os << ": " << std::endl << error->message;
// remove CR // remove CR
std::string msg = os.str().substr(0, os.str().size() - 1); std::string msg = os.str().substr(0, os.str().size() - 1);
config_error ex( msg ); throw config_error(msg, error->line, error->file);
os.str("");
os << "(encountered in file '" << error->file << "' at line "
<< error->line << ")";
ex.append_context( os.str() );
throw ex;
} }
} }
@ -110,21 +103,21 @@ public:
<< std::endl; << 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_); xmlDocPtr doc = xmlCtxtReadFd(ctx_, fd, url_, encoding_, options_);
load(doc, pt); load(doc, node);
} }
void load_string( std::string const& buffer, ptree & pt, std::string const & base_path ) void load_string(std::string const& buffer, xml_node &node, std::string const & base_path)
{ {
if (!base_path.empty()) if (!base_path.empty())
{ {
boost::filesystem::path path(base_path); 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 '") + throw config_error(string("Could not locate base_path '") +
base_path + "': file or directory does not exist"); base_path + "': file or directory does not exist");
} }
@ -132,12 +125,12 @@ public:
xmlDocPtr doc = xmlCtxtReadMemory(ctx_, buffer.data(), buffer.length(), base_path.c_str(), encoding_, options_); 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_ ); xmlError * error = xmlCtxtGetLastError( ctx_ );
std::ostringstream os; std::ostringstream os;
@ -146,10 +139,10 @@ public:
{ {
os << ": " << std::endl << error->message; os << ": " << std::endl << error->message;
} }
throw config_error(os.str()); throw config_error(os.str(), error->line, error->file);
} }
int iXIncludeReturn = xmlXIncludeProcessFlags( doc, options_ ); int iXIncludeReturn = xmlXIncludeProcessFlags(doc, options_);
if (iXIncludeReturn < 0) if (iXIncludeReturn < 0)
{ {
@ -157,63 +150,47 @@ public:
throw config_error("XML XInclude error. One or more files failed to load."); throw config_error("XML XInclude error. One or more files failed to load.");
} }
xmlNode * root = xmlDocGetRootElement( doc ); xmlNode * root = xmlDocGetRootElement(doc);
if ( ! root ) { if (!root) {
xmlFreeDoc(doc); xmlFreeDoc(doc);
throw config_error("XML document is empty."); throw config_error("XML document is empty.");
} }
populate_tree( root, pt ); populate_tree(root, node);
xmlFreeDoc(doc); xmlFreeDoc(doc);
} }
private: 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( "<xmlattr>", ptree() )); node.add_attribute((char *)attributes->name, (char *)attributes->children->content);
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 );
}
} }
} }
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 ) for (; cur_node; cur_node = cur_node->next )
{ {
switch (cur_node->type) switch (cur_node->type)
{ {
case XML_ELEMENT_NODE: case XML_ELEMENT_NODE:
{ {
ptree::iterator it = pt.push_back( ptree::value_type(
(char*)cur_node->name, ptree() )); xml_node &new_node = node.add_child((char *)cur_node->name, cur_node->line, false);
append_attributes( cur_node->properties, it->second); append_attributes(cur_node->properties, new_node);
populate_tree( cur_node->children, it->second ); populate_tree(cur_node->children, new_node);
} }
break; break;
case XML_TEXT_NODE: case XML_TEXT_NODE:
{ {
std::string trimmed = boost::algorithm::trim_copy(std::string((char*)cur_node->content)); std::string trimmed = boost::algorithm::trim_copy(std::string((char*)cur_node->content));
if (trimmed.empty()) break; if (trimmed.empty()) break; //Don't add empty text nodes
ptree::iterator it = pt.push_back(ptree::value_type("<xmltext>", ptree())); node.add_child(trimmed, cur_node->line, true);
it->second.put_value(trimmed);
} }
break; break;
case XML_COMMENT_NODE: case XML_COMMENT_NODE:
{
ptree::iterator it = pt.push_back(
ptree::value_type( "<xmlcomment>", ptree() ));
it->second.put_value( (char*) cur_node->content );
}
break; break;
default: default:
break; break;
@ -228,15 +205,15 @@ private:
const char *url_; const char *url_;
}; };
void read_xml2( std::string const & filename, boost::property_tree::ptree & pt) void read_xml(std::string const & filename, xml_node &node)
{ {
libxml2_loader loader; 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_xml_string(std::string const & str, xml_node &node, std::string const & base_path)
{ {
libxml2_loader loader; libxml2_loader loader;
loader.load_string( str, pt, base_path ); loader.load_string(str, node, base_path);
} }
} // end of namespace mapnik } // end of namespace mapnik

File diff suppressed because it is too large Load diff

View file

@ -22,15 +22,15 @@
//$Id$ //$Id$
#include <mapnik/metawriter_factory.hpp> #include <mapnik/metawriter_factory.hpp>
#include <mapnik/ptree_helpers.hpp>
#include <mapnik/metawriter_json.hpp> #include <mapnik/metawriter_json.hpp>
#include <mapnik/metawriter_inmem.hpp> #include <mapnik/metawriter_inmem.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/ptree_helpers.hpp>
#include <mapnik/config_error.hpp>
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
using boost::property_tree::ptree;
using boost::optional; using boost::optional;
using std::string; using std::string;
@ -38,20 +38,21 @@ namespace mapnik
{ {
metawriter_ptr metawriter_ptr
metawriter_create(const boost::property_tree::ptree &pt) { metawriter_create(xml_node const& pt)
{
metawriter_ptr writer; metawriter_ptr writer;
string type = get_attr<string>(pt, "type"); string type = pt.get_attr<string>("type");
optional<string> properties = get_opt_attr<string>(pt, "default-output"); optional<string> properties = pt.get_opt_attr<string>("default-output");
if (type == "json") { if (type == "json") {
string file = get_attr<string>(pt, "file"); string file = pt.get_attr<string>("file");
metawriter_json_ptr json = boost::make_shared<metawriter_json>(properties, parse_path(file)); metawriter_json_ptr json = boost::make_shared<metawriter_json>(properties, parse_path(file));
optional<boolean> output_empty = get_opt_attr<boolean>(pt, "output-empty"); optional<boolean> output_empty = pt.get_opt_attr<boolean>("output-empty");
if (output_empty) { if (output_empty) {
json->set_output_empty(*output_empty); json->set_output_empty(*output_empty);
} }
optional<boolean> pixel_coordinates = get_opt_attr<boolean>(pt, "pixel-coordinates"); optional<boolean> pixel_coordinates = pt.get_opt_attr<boolean>("pixel-coordinates");
if (pixel_coordinates) { if (pixel_coordinates) {
json->set_pixel_coordinates(*pixel_coordinates); json->set_pixel_coordinates(*pixel_coordinates);
} }
@ -61,14 +62,16 @@ metawriter_create(const boost::property_tree::ptree &pt) {
metawriter_inmem_ptr inmem = boost::make_shared<metawriter_inmem>(properties); metawriter_inmem_ptr inmem = boost::make_shared<metawriter_inmem>(properties);
writer = inmem; writer = inmem;
} else { } else {
throw config_error(string("Unknown type '") + type + "'"); throw config_error(string("Unknown type '") + type + "'", pt);
} }
return writer; return writer;
} }
void void
metawriter_save(const metawriter_ptr &metawriter, ptree &metawriter_node, bool explicit_defaults) { metawriter_save(const metawriter_ptr &metawriter,
boost::property_tree::ptree &metawriter_node, bool explicit_defaults)
{
metawriter_json *json = dynamic_cast<metawriter_json *>(metawriter.get()); metawriter_json *json = dynamic_cast<metawriter_json *>(metawriter.get());
if (json) { if (json) {

View file

@ -21,6 +21,7 @@
*****************************************************************************/ *****************************************************************************/
#include <mapnik/palette.hpp> #include <mapnik/palette.hpp>
#include <mapnik/config_error.hpp>
namespace mapnik namespace mapnik
{ {

View file

@ -1,4 +1,28 @@
/*****************************************************************************
*
* 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 <mapnik/processed_text.hpp> #include <mapnik/processed_text.hpp>
#include <mapnik/config_error.hpp>
namespace mapnik namespace mapnik
{ {
@ -43,7 +67,7 @@ string_info &processed_text::get_string_info()
{ {
if (!p.fontset.get_name().empty()) if (!p.fontset.get_name().empty())
{ {
throw config_error("Unable to find specified font set '" + p.face_name + "'"); throw config_error("Unable to find specified font set '" + p.fontset.get_name() + "'");
} else if (!p.face_name.empty()) { } else if (!p.face_name.empty()) {
throw config_error("Unable to find specified font face '" + p.face_name + "'"); throw config_error("Unable to find specified font face '" + p.face_name + "'");
} else { } else {

171
src/rapidxml_loader.cpp Normal file
View file

@ -0,0 +1,171 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2011 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
*
*****************************************************************************/
#ifdef HAVE_LIBXML2
#error HAVE_LIBXML2 defined but compiling rapidxml_loader.cpp!
#endif
// mapnik
#include <mapnik/xml_loader.hpp>
#include <boost/property_tree/detail/xml_parser_read_rapidxml.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/config_error.hpp>
// boost
#include <boost/utility.hpp>
#include <boost/algorithm/string/trim.hpp>
// stl
#include <iostream>
#include <fstream>
using namespace std;
namespace rapidxml = boost::property_tree::detail::rapidxml;
namespace mapnik
{
class rapidxml_loader : boost::noncopyable
{
public:
rapidxml_loader(const char *encoding = NULL) :
filename_()
{
}
~rapidxml_loader()
{
}
void load(const std::string & filename, xml_node &node)
{
filename_ = filename;
std::basic_ifstream<char> stream(filename.c_str());
if (!stream)
{
throw config_error("Could not load map file", 0, filename);
}
// TODO: stream.imbue(loc);
load(stream, node);
}
void load(std::basic_istream<char> &stream, xml_node &node)
{
stream.unsetf(std::ios::skipws);
std::vector<char> v(std::istreambuf_iterator<char>(stream.rdbuf()),
std::istreambuf_iterator<char>());
if (!stream.good())
{
throw config_error("Could not load map file", 0, filename_);
}
v.push_back(0); // zero-terminate
try
{
// Parse using appropriate flags
const int f_tws = rapidxml::parse_normalize_whitespace
| rapidxml::parse_trim_whitespace;
rapidxml::xml_document<> doc;
doc.parse<f_tws>(&v.front());
for (rapidxml::xml_node<char> *child = doc.first_node();
child; child = child->next_sibling())
{
populate_tree(child, node);
}
}
catch (rapidxml::parse_error &e)
{
long line = static_cast<long>(
std::count(&v.front(), e.where<char>(), '\n') + 1);
throw config_error(e.what(), line, filename_);
}
}
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)) {
// throw config_error(string("Could not locate base_path '") +
// base_path + "': file or directory does not exist");
// }
// }
load(buffer, node);
}
private:
void populate_tree(rapidxml::xml_node<char> *cur_node, xml_node &node)
{
switch (cur_node->type())
{
case rapidxml::node_element:
{
xml_node &new_node = node.add_child((char *)cur_node->name(), 0, false);
// Copy attributes
for (rapidxml::xml_attribute<char> *attr = cur_node->first_attribute();
attr; attr = attr->next_attribute())
{
new_node.add_attribute(attr->name(), attr->value());
}
// Copy children
for (rapidxml::xml_node<char> *child = cur_node->first_node();
child; child = child->next_sibling())
{
populate_tree(child, new_node);
}
}
break;
// Data nodes
case rapidxml::node_data:
case rapidxml::node_cdata:
{
std::string trimmed = boost::algorithm::trim_copy(std::string(cur_node->value()));
if (trimmed.empty()) break; //Don't add empty text nodes
node.add_child(trimmed, 0, true);
}
break;
default:
break;
}
}
private:
std::string filename_;
};
void read_xml(std::string const & filename, xml_node &node)
{
rapidxml_loader loader;
loader.load(filename, node);
}
void read_xml_string(std::string const & str, xml_node &node, std::string const & base_path)
{
rapidxml_loader loader;
loader.load_string(str, node, base_path);
}
} // end of namespace mapnik

View file

@ -24,6 +24,7 @@
#include <mapnik/svg/svg_parser.hpp> #include <mapnik/svg/svg_parser.hpp>
#include <mapnik/svg/svg_path_parser.hpp> #include <mapnik/svg/svg_path_parser.hpp>
#include <mapnik/config_error.hpp>
#include "agg_ellipse.h" #include "agg_ellipse.h"
#include "agg_rounded_rect.h" #include "agg_rounded_rect.h"

View file

@ -20,9 +20,14 @@
* *
*****************************************************************************/ *****************************************************************************/
//mapnik
#include <mapnik/text_placements/list.hpp> #include <mapnik/text_placements/list.hpp>
#include <mapnik/xml_node.hpp>
//boost
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
namespace mapnik namespace mapnik
{ {
@ -58,8 +63,7 @@ text_symbolizer_properties & text_placements_list::get(unsigned i)
text_placement_info_ptr text_placements_list::get_placement_info(double scale_factor) const text_placement_info_ptr text_placements_list::get_placement_info(double scale_factor) const
{ {
return text_placement_info_ptr( return boost::make_shared<text_placement_info_list>(this, scale_factor);
boost::make_shared<text_placement_info_list>(this, scale_factor));
} }
text_placements_list::text_placements_list() : text_placements(), list_(0) text_placements_list::text_placements_list() : text_placements(), list_(0)
@ -83,20 +87,19 @@ unsigned text_placements_list::size() const
return list_.size(); return list_.size();
} }
text_placements_ptr text_placements_list::from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets) text_placements_ptr text_placements_list::from_xml(xml_node const &xml, fontset_map const & fontsets)
{ {
using boost::property_tree::ptree; using boost::property_tree::ptree;
text_placements_list *list = new text_placements_list; text_placements_list *list = new text_placements_list;
text_placements_ptr ptr = text_placements_ptr(list); text_placements_ptr ptr = text_placements_ptr(list);
list->defaults.from_xml(xml, fontsets); list->defaults.from_xml(xml, fontsets);
ptree::const_iterator itr = xml.begin(); xml_node::const_iterator itr = xml.begin();
ptree::const_iterator end = xml.end(); xml_node::const_iterator end = xml.end();
for( ;itr != end; ++itr) for( ;itr != end; ++itr)
{ {
if ((itr->first.find('<') != std::string::npos) || (itr->first != "Placement")) continue; if (itr->is_text() || !itr->is("Placement")) continue;
//TODO: ensure_attrs(symIter->second, "TextSymbolizer/Placement", s_common.str());
text_symbolizer_properties &p = list->add(); text_symbolizer_properties &p = list->add();
p.from_xml(itr->second, fontsets); p.from_xml(*itr, fontsets);
//TODO: if (strict_ && //TODO: if (strict_ &&
// !p.format.fontset.size()) // !p.format.fontset.size())
// ensure_font_face(p.format.face_name); // ensure_font_face(p.format.face_name);

View file

@ -24,6 +24,7 @@
#include <mapnik/text_placements/simple.hpp> #include <mapnik/text_placements/simple.hpp>
#include <mapnik/text_placements/list.hpp> #include <mapnik/text_placements/list.hpp>
#include <mapnik/text_placements/dummy.hpp> #include <mapnik/text_placements/dummy.hpp>
#include <mapnik/config_error.hpp>
namespace mapnik namespace mapnik
{ {
@ -46,10 +47,10 @@ void registry::register_name(std::string name, from_xml_function_ptr ptr, bool o
} }
} }
text_placements_ptr registry::from_xml(std::string name, const boost::property_tree::ptree &xml, fontset_map const& fontsets) text_placements_ptr registry::from_xml(std::string name, xml_node const& xml, fontset_map const& fontsets)
{ {
std::map<std::string, from_xml_function_ptr>::const_iterator itr = map_.find(name); std::map<std::string, from_xml_function_ptr>::const_iterator itr = map_.find(name);
if (itr == map_.end()) throw config_error("Unknown placement-type '" + name + "'"); if (itr == map_.end()) throw config_error("Unknown placement-type '" + name + "'", xml);
return itr->second(xml, fontsets); return itr->second(xml, fontsets);
} }
} //ns formatting } //ns formatting

View file

@ -23,6 +23,7 @@
// mapnik // mapnik
#include <mapnik/text_placements/simple.hpp> #include <mapnik/text_placements/simple.hpp>
#include <mapnik/ptree_helpers.hpp> #include <mapnik/ptree_helpers.hpp>
#include <mapnik/xml_node.hpp>
// boost // boost
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/qi.hpp>
@ -102,8 +103,7 @@ bool text_placement_info_simple::next_position_only()
text_placement_info_ptr text_placements_simple::get_placement_info( text_placement_info_ptr text_placements_simple::get_placement_info(
double scale_factor) const double scale_factor) const
{ {
return text_placement_info_ptr( return boost::make_shared<text_placement_info_simple>(this, scale_factor);
boost::make_shared<text_placement_info_simple>(this, scale_factor));
} }
/** Position string: [POS][SIZE] /** Position string: [POS][SIZE]
@ -144,10 +144,12 @@ void text_placements_simple::set_positions(std::string positions)
(direction_name[push_back(phoenix::ref(direction_), _1)] % ',') >> *(',' >> qi::float_[push_back(phoenix::ref(text_sizes_), _1)]), (direction_name[push_back(phoenix::ref(direction_), _1)] % ',') >> *(',' >> qi::float_[push_back(phoenix::ref(text_sizes_), _1)]),
space space
); );
if (first != last) { if (first != last)
{
std::cerr << "WARNING: Could not parse text_placement_simple placement string ('" << positions << "').\n"; std::cerr << "WARNING: Could not parse text_placement_simple placement string ('" << positions << "').\n";
} }
if (direction_.size() == 0) { if (direction_.size() == 0)
{
std::cerr << "WARNING: text_placements_simple with no valid placements! ('"<< positions<<"')\n"; std::cerr << "WARNING: text_placements_simple with no valid placements! ('"<< positions<<"')\n";
} }
} }
@ -167,10 +169,10 @@ std::string text_placements_simple::get_positions()
return positions_; //TODO: Build string from data in direction_ and text_sizes_ return positions_; //TODO: Build string from data in direction_ and text_sizes_
} }
text_placements_ptr text_placements_simple::from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets) text_placements_ptr text_placements_simple::from_xml(xml_node const &xml, fontset_map const & fontsets)
{ {
text_placements_ptr ptr = boost::make_shared<text_placements_simple>( text_placements_ptr ptr = boost::make_shared<text_placements_simple>(
get_attr<std::string>(xml, "placements", "X")); xml.get_attr<std::string>("placements", "X"));
ptr->defaults.from_xml(xml, fontsets); ptr->defaults.from_xml(xml, fontsets);
return ptr; return ptr;
} }

View file

@ -25,6 +25,8 @@
#include <mapnik/ptree_helpers.hpp> #include <mapnik/ptree_helpers.hpp>
#include <mapnik/expression_string.hpp> #include <mapnik/expression_string.hpp>
#include <mapnik/formatting/text.hpp> #include <mapnik/formatting/text.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/config_error.hpp>
// boost // boost
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
@ -79,45 +81,45 @@ formatting::node_ptr text_symbolizer_properties::format_tree() const
return tree_; return tree_;
} }
void text_symbolizer_properties::from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets) void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const & fontsets)
{ {
optional<label_placement_e> placement_ = get_opt_attr<label_placement_e>(sym, "placement"); optional<label_placement_e> placement_ = sym.get_opt_attr<label_placement_e>("placement");
if (placement_) label_placement = *placement_; if (placement_) label_placement = *placement_;
optional<vertical_alignment_e> valign_ = get_opt_attr<vertical_alignment_e>(sym, "vertical-alignment"); optional<vertical_alignment_e> valign_ = sym.get_opt_attr<vertical_alignment_e>("vertical-alignment");
if (valign_) valign = *valign_; if (valign_) valign = *valign_;
optional<unsigned> text_ratio_ = get_opt_attr<unsigned>(sym, "text-ratio"); optional<unsigned> text_ratio_ = sym.get_opt_attr<unsigned>("text-ratio");
if (text_ratio_) text_ratio = *text_ratio_; if (text_ratio_) text_ratio = *text_ratio_;
optional<unsigned> wrap_width_ = get_opt_attr<unsigned>(sym, "wrap-width"); optional<unsigned> wrap_width_ = sym.get_opt_attr<unsigned>("wrap-width");
if (wrap_width_) wrap_width = *wrap_width_; if (wrap_width_) wrap_width = *wrap_width_;
optional<unsigned> label_position_tolerance_ = get_opt_attr<unsigned>(sym, "label-position-tolerance"); optional<unsigned> label_position_tolerance_ = sym.get_opt_attr<unsigned>("label-position-tolerance");
if (label_position_tolerance_) label_position_tolerance = *label_position_tolerance_; if (label_position_tolerance_) label_position_tolerance = *label_position_tolerance_;
optional<unsigned> spacing_ = get_opt_attr<unsigned>(sym, "spacing"); optional<unsigned> spacing_ = sym.get_opt_attr<unsigned>("spacing");
if (spacing_) label_spacing = *spacing_; if (spacing_) label_spacing = *spacing_;
optional<unsigned> minimum_distance_ = get_opt_attr<unsigned>(sym, "minimum-distance"); optional<unsigned> minimum_distance_ = sym.get_opt_attr<unsigned>("minimum-distance");
if (minimum_distance_) minimum_distance = *minimum_distance_; if (minimum_distance_) minimum_distance = *minimum_distance_;
optional<unsigned> min_padding_ = get_opt_attr<unsigned>(sym, "minimum-padding"); optional<unsigned> min_padding_ = sym.get_opt_attr<unsigned>("minimum-padding");
if (min_padding_) minimum_padding = *min_padding_; if (min_padding_) minimum_padding = *min_padding_;
optional<unsigned> min_path_length_ = get_opt_attr<unsigned>(sym, "minimum-path-length"); optional<unsigned> min_path_length_ = sym.get_opt_attr<unsigned>("minimum-path-length");
if (min_path_length_) minimum_path_length = *min_path_length_; if (min_path_length_) minimum_path_length = *min_path_length_;
optional<boolean> avoid_edges_ = get_opt_attr<boolean>(sym, "avoid-edges"); optional<boolean> avoid_edges_ = sym.get_opt_attr<boolean>("avoid-edges");
if (avoid_edges_) avoid_edges = *avoid_edges_; if (avoid_edges_) avoid_edges = *avoid_edges_;
optional<boolean> allow_overlap_ = get_opt_attr<boolean>(sym, "allow-overlap"); optional<boolean> allow_overlap_ = sym.get_opt_attr<boolean>("allow-overlap");
if (allow_overlap_) allow_overlap = *allow_overlap_; if (allow_overlap_) allow_overlap = *allow_overlap_;
optional<horizontal_alignment_e> halign_ = get_opt_attr<horizontal_alignment_e>(sym, "horizontal-alignment"); optional<horizontal_alignment_e> halign_ = sym.get_opt_attr<horizontal_alignment_e>("horizontal-alignment");
if (halign_) halign = *halign_; if (halign_) halign = *halign_;
optional<justify_alignment_e> jalign_ = get_opt_attr<justify_alignment_e>(sym, "justify-alignment"); optional<justify_alignment_e> jalign_ = sym.get_opt_attr<justify_alignment_e>("justify-alignment");
if (jalign_) jalign = *jalign_; if (jalign_) jalign = *jalign_;
/* Attributes needing special care */ /* Attributes needing special care */
optional<std::string> orientation_ = get_opt_attr<std::string>(sym, "orientation"); optional<std::string> orientation_ = sym.get_opt_attr<std::string>("orientation");
if (orientation_) orientation = parse_expression(*orientation_, "utf8"); if (orientation_) orientation = parse_expression(*orientation_, "utf8");
optional<double> dx = get_opt_attr<double>(sym, "dx"); optional<double> dx = sym.get_opt_attr<double>("dx");
if (dx) displacement.first = *dx; if (dx) displacement.first = *dx;
optional<double> dy = get_opt_attr<double>(sym, "dy"); optional<double> dy = sym.get_opt_attr<double>("dy");
if (dy) displacement.second = *dy; if (dy) displacement.second = *dy;
optional<double> max_char_angle_delta_ = get_opt_attr<double>(sym, "max-char-angle-delta"); optional<double> max_char_angle_delta_ = sym.get_opt_attr<double>("max-char-angle-delta");
if (max_char_angle_delta_) max_char_angle_delta=(*max_char_angle_delta_)*(M_PI/180); if (max_char_angle_delta_) max_char_angle_delta=(*max_char_angle_delta_)*(M_PI/180);
optional<std::string> name_ = get_opt_attr<std::string>(sym, "name"); optional<std::string> name_ = sym.get_opt_attr<std::string>("name");
if (name_) { if (name_) {
std::clog << "### WARNING: Using 'name' in TextSymbolizer/ShieldSymbolizer is deprecated!\n"; std::clog << "### WARNING: Using 'name' in TextSymbolizer/ShieldSymbolizer is deprecated!\n";
set_old_style_expression(parse_expression(*name_, "utf8")); set_old_style_expression(parse_expression(*name_, "utf8"));
@ -241,34 +243,34 @@ char_properties::char_properties() :
} }
void char_properties::from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets) void char_properties::from_xml(xml_node const& sym, fontset_map const& fontsets)
{ {
optional<double> text_size_ = get_opt_attr<double>(sym, "size"); optional<double> text_size_ = sym.get_opt_attr<double>("size");
if (text_size_) text_size = *text_size_; if (text_size_) text_size = *text_size_;
optional<double> character_spacing_ = get_opt_attr<double>(sym, "character-spacing"); optional<double> character_spacing_ = sym.get_opt_attr<double>("character-spacing");
if (character_spacing_) character_spacing = *character_spacing_; if (character_spacing_) character_spacing = *character_spacing_;
optional<color> fill_ = get_opt_attr<color>(sym, "fill"); optional<color> fill_ = sym.get_opt_attr<color>("fill");
if (fill_) fill = *fill_; if (fill_) fill = *fill_;
optional<color> halo_fill_ = get_opt_attr<color>(sym, "halo-fill"); optional<color> halo_fill_ = sym.get_opt_attr<color>("halo-fill");
if (halo_fill_) halo_fill = *halo_fill_; if (halo_fill_) halo_fill = *halo_fill_;
optional<double> halo_radius_ = get_opt_attr<double>(sym, "halo-radius"); optional<double> halo_radius_ = sym.get_opt_attr<double>("halo-radius");
if (halo_radius_) halo_radius = *halo_radius_; if (halo_radius_) halo_radius = *halo_radius_;
optional<boolean> wrap_before_ = get_opt_attr<boolean>(sym, "wrap-before"); optional<boolean> wrap_before_ = sym.get_opt_attr<boolean>("wrap-before");
if (wrap_before_) wrap_before = *wrap_before_; if (wrap_before_) wrap_before = *wrap_before_;
optional<text_transform_e> tconvert_ = get_opt_attr<text_transform_e>(sym, "text-transform"); optional<text_transform_e> tconvert_ = sym.get_opt_attr<text_transform_e>("text-transform");
if (tconvert_) text_transform = *tconvert_; if (tconvert_) text_transform = *tconvert_;
optional<double> line_spacing_ = get_opt_attr<double>(sym, "line-spacing"); optional<double> line_spacing_ = sym.get_opt_attr<double>("line-spacing");
if (line_spacing_) line_spacing = *line_spacing_; if (line_spacing_) line_spacing = *line_spacing_;
optional<double> opacity_ = get_opt_attr<double>(sym, "opacity"); optional<double> opacity_ = sym.get_opt_attr<double>("opacity");
if (opacity_) text_opacity = *opacity_; if (opacity_) text_opacity = *opacity_;
optional<std::string> wrap_char_ = get_opt_attr<std::string>(sym, "wrap-character"); optional<std::string> wrap_char_ = sym.get_opt_attr<std::string>("wrap-character");
if (wrap_char_ && (*wrap_char_).size() > 0) wrap_char = ((*wrap_char_)[0]); if (wrap_char_ && (*wrap_char_).size() > 0) wrap_char = ((*wrap_char_)[0]);
optional<std::string> face_name_ = get_opt_attr<std::string>(sym, "face-name"); optional<std::string> face_name_ = sym.get_opt_attr<std::string>("face-name");
if (face_name_) if (face_name_)
{ {
face_name = *face_name_; face_name = *face_name_;
} }
optional<std::string> fontset_name_ = get_opt_attr<std::string>(sym, "fontset-name"); optional<std::string> fontset_name_ = sym.get_opt_attr<std::string>("fontset-name");
if (fontset_name_) { if (fontset_name_) {
std::map<std::string,font_set>::const_iterator itr = fontsets.find(*fontset_name_); std::map<std::string,font_set>::const_iterator itr = fontsets.find(*fontset_name_);
if (itr != fontsets.end()) if (itr != fontsets.end())
@ -277,16 +279,16 @@ void char_properties::from_xml(boost::property_tree::ptree const &sym, fontset_m
} }
else else
{ {
throw config_error("Unable to find any fontset named '" + *fontset_name_ + "'"); throw config_error("Unable to find any fontset named '" + *fontset_name_ + "'", sym);
} }
} }
if (!face_name.empty() && !fontset.get_name().empty()) if (!face_name.empty() && !fontset.get_name().empty())
{ {
throw config_error(std::string("Can't have both face-name and fontset-name")); throw config_error("Can't have both face-name and fontset-name", sym);
} }
if (face_name.empty() && fontset.get_name().empty()) if (face_name.empty() && fontset.get_name().empty())
{ {
throw config_error(std::string("Must have face-name or fontset-name")); throw config_error("Must have face-name or fontset-name", sym);
} }
} }

483
src/xml_tree.cpp Normal file
View file

@ -0,0 +1,483 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
//mapnik
#include <mapnik/xml_tree.hpp>
#include <mapnik/util/conversions.hpp>
#include <mapnik/enumeration.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/gamma_method.hpp>
#include <mapnik/line_symbolizer.hpp>
#include <mapnik/feature_type_style.hpp>
#include <mapnik/text_properties.hpp>
#include <mapnik/config_error.hpp>
//boost
#include <boost/lexical_cast.hpp>
namespace mapnik
{
template <typename T>
inline boost::optional<T> fast_cast(xml_tree const& tree, std::string const& value)
{
try
{
return boost::lexical_cast<T>(value);
}
catch (boost::bad_lexical_cast const& ex)
{
return boost::optional<T>();
}
}
template <>
inline boost::optional<int> fast_cast(xml_tree const& tree, std::string const& value)
{
int result;
if (mapnik::conversions::string2int(value, result))
return boost::optional<int>(result);
return boost::optional<int>();
}
template <>
inline boost::optional<double> fast_cast(xml_tree const& tree, std::string const& value)
{
double result;
if (mapnik::conversions::string2double(value, result))
return boost::optional<double>(result);
return boost::optional<double>();
}
template <>
inline boost::optional<float> fast_cast(xml_tree const& tree, std::string const& value)
{
float result;
if (mapnik::conversions::string2float(value, result))
return boost::optional<float>(result);
return boost::optional<float>();
}
template <>
inline boost::optional<std::string> fast_cast(xml_tree const& tree, std::string const& value)
{
return value;
}
template <>
inline boost::optional<color> fast_cast(xml_tree const& tree, std::string const& value)
{
mapnik::color c;
if (mapnik::color_factory::parse_from_string(c, value, tree.color_grammar))
{
return c;
}
else
{
throw config_error("Failed to parse color '"+value+"'");
}
}
template <>
inline boost::optional<expression_ptr> fast_cast(xml_tree const& tree, std::string const& value)
{
expression_ptr expr(boost::make_shared<expr_node>(true));
if (expression_factory::parse_from_string(expr, value, tree.expr_grammar))
{
return expr;
} else
{
throw mapnik::config_error("Failed to parse expression '" + value + "'");
}
}
/****************************************************************************/
class boolean;
template <typename T>
struct name_trait
{
static std::string name()
{
return "<unknown>";
}
// missing name_trait for type ...
// if you get here you are probably using a new type
// in the XML file. Just add a name trait for the new
// type below.
BOOST_STATIC_ASSERT( sizeof(T) == 0 );
};
#define DEFINE_NAME_TRAIT( type, type_name ) \
template <> \
struct name_trait<type> \
{ \
static std::string name() { return std::string("type ") + type_name; } \
};
DEFINE_NAME_TRAIT( double, "double")
DEFINE_NAME_TRAIT( float, "float")
DEFINE_NAME_TRAIT( unsigned, "unsigned")
DEFINE_NAME_TRAIT( boolean, "boolean")
DEFINE_NAME_TRAIT( int, "integer" )
DEFINE_NAME_TRAIT( std::string, "string" )
DEFINE_NAME_TRAIT( color, "color" )
DEFINE_NAME_TRAIT(expression_ptr, "expression_ptr" )
template <typename ENUM, int MAX>
struct name_trait< mapnik::enumeration<ENUM, MAX> >
{
typedef enumeration<ENUM, MAX> Enum;
static std::string name()
{
std::string value_list("one of [");
for (unsigned i = 0; i < Enum::MAX; ++i)
{
value_list += Enum::get_string( i );
if ( i + 1 < Enum::MAX ) value_list += ", ";
}
value_list += "]";
return value_list;
}
};
/****************************************************************************/
xml_tree::xml_tree(std::string const& encoding)
: node_(*this, "<root>"),
file_(),
tr_(encoding),
color_grammar(),
expr_grammar(tr_)
{
node_.set_processed(true); //root node is always processed
}
void xml_tree::set_filename(std::string fn)
{
file_ = fn;
}
std::string const& xml_tree::filename() const
{
return file_;
}
xml_node &xml_tree::root()
{
return node_;
}
/****************************************************************************/
xml_attribute::xml_attribute(std::string const& value_)
: value(value_), processed(false)
{
}
/****************************************************************************/
node_not_found::node_not_found(std::string node_name)
: node_name_(node_name)
{
}
const char* node_not_found::what() const throw()
{
return ("Node "+node_name_+ "not found").c_str();
}
node_not_found::~node_not_found() throw()
{
}
attribute_not_found::attribute_not_found(
std::string const& node_name,
std::string const& attribute_name)
:
node_name_(node_name),
attribute_name_(attribute_name)
{
}
const char* attribute_not_found::what() const throw()
{
return ("Attribute '" + attribute_name_ +"' not found in node '"+node_name_+ "'").c_str();
}
attribute_not_found::~attribute_not_found() throw()
{
}
more_than_one_child::more_than_one_child(std::string const& node_name)
: node_name_(node_name)
{
}
const char* more_than_one_child::what() const throw()
{
return ("More than one child node in node '" + node_name_ +"'").c_str();
}
more_than_one_child::~more_than_one_child() throw()
{
}
/****************************************************************************/
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::xml_text = "<xmltext>";
std::string const& xml_node::name() const
{
if (!text_node_)
return name_;
else
return xml_text;
}
std::string const& xml_node::text() const
{
if (text_node_)
{
processed_ = true;
return name_;
} else
{
throw config_error("text() called on non-text node", *this);
}
}
std::string const& xml_node::filename() const
{
return tree_.filename();
}
bool xml_node::is_text() const
{
return text_node_;
}
bool xml_node::is(std::string const& name) const
{
if (name_ == name)
{
processed_ = true;
return true;
}
return false;
}
xml_node &xml_node::add_child(std::string const& name, unsigned line, bool text_node)
{
children_.push_back(xml_node(tree_, name, line, text_node));
return children_.back();
}
void xml_node::add_attribute(std::string const& name, std::string const& value)
{
attributes_.insert(std::make_pair(name,xml_attribute(value)));
}
xml_node::attribute_map const& xml_node::get_attributes() const
{
return attributes_;
}
void xml_node::set_processed(bool processed) const
{
processed_ = processed;
}
bool xml_node::processed() const
{
return processed_;
}
xml_node::const_iterator xml_node::begin() const
{
return children_.begin();
}
xml_node::const_iterator xml_node::end() const
{
return children_.end();
}
xml_node & xml_node::get_child(std::string const& name)
{
std::list<xml_node>::iterator itr = children_.begin();
std::list<xml_node>::iterator end = children_.end();
for (; itr != end; itr++)
{
if (!(itr->text_node_) && itr->name_ == name)
{
itr->set_processed(true);
return *itr;
}
}
throw node_not_found(name);
}
xml_node const& xml_node::get_child(std::string const& name) const
{
xml_node const* node = get_opt_child(name);
if (!node) throw node_not_found(name);
return *node;
}
xml_node const* xml_node::get_opt_child(std::string const& name) const
{
const_iterator itr = children_.begin();
const_iterator end = children_.end();
for (; itr != end; itr++)
{
if (!(itr->text_node_) && itr->name_ == name)
{
itr->set_processed(true);
return &(*itr);
}
}
return 0;
}
bool xml_node::has_child(std::string const& name) const
{
return get_opt_child(name) != 0;
}
template <typename T>
boost::optional<T> xml_node::get_opt_attr(std::string const& name) const
{
std::map<std::string, xml_attribute>::const_iterator itr = attributes_.find(name);
if (itr == attributes_.end()) return boost::optional<T>();
itr->second.processed = true;
boost::optional<T> result = fast_cast<T>(tree_, itr->second.value);
if (!result)
{
throw config_error(std::string("Failed to parse attribute '") +
name + "'. Expected " + name_trait<T>::name() +
" but got '" + itr->second.value + "'", *this);
}
return result;
}
template <typename T>
T xml_node::get_attr(std::string const& name, T const& default_value) const
{
boost::optional<T> value = get_opt_attr<T>(name);
if (value) return *value;
return default_value;
}
template <typename T>
T xml_node::get_attr(std::string const& name) const
{
boost::optional<T> value = get_opt_attr<T>(name);
if (value) return *value;
throw attribute_not_found(name_, name);
}
std::string xml_node::get_text() const
{
if (children_.size() == 0)
{
return "";
}
if (children_.size() == 1)
{
return children_.front().text();
}
throw more_than_one_child(name_);
}
template <typename T>
T xml_node::get_value() const
{
boost::optional<T> result = fast_cast<T>(tree_, get_text());
if (!result)
{
throw config_error(std::string("Failed to parse value. Expected ")
+ name_trait<T>::name() +
" but got '" + get_text() + "'", *this);
}
return *result;
}
unsigned xml_node::line() const
{
return line_;
}
#define compile_get_opt_attr(T) template boost::optional<T> xml_node::get_opt_attr<T>(std::string const&) const
#define compile_get_attr(T) template T xml_node::get_attr<T>(std::string const&) const; template T xml_node::get_attr<T>(std::string const&, T const&) const
#define compile_get_value(T) template T xml_node::get_value<T>() const
compile_get_opt_attr(boolean);
compile_get_opt_attr(std::string);
compile_get_opt_attr(unsigned);
compile_get_opt_attr(float);
compile_get_opt_attr(double);
compile_get_opt_attr(color);
compile_get_opt_attr(gamma_method_e);
compile_get_opt_attr(line_rasterizer_e);
compile_get_opt_attr(line_join_e);
compile_get_opt_attr(line_cap_e);
compile_get_opt_attr(text_transform_e);
compile_get_opt_attr(label_placement_e);
compile_get_opt_attr(vertical_alignment_e);
compile_get_opt_attr(horizontal_alignment_e);
compile_get_opt_attr(justify_alignment_e);
compile_get_opt_attr(expression_ptr);
compile_get_attr(std::string);
compile_get_attr(filter_mode_e);
compile_get_attr(point_placement_e);
compile_get_attr(marker_placement_e);
compile_get_attr(marker_type_e);
compile_get_attr(pattern_alignment_e);
compile_get_attr(line_rasterizer_e);
compile_get_attr(colorizer_mode);
compile_get_attr(double);
compile_get_value(int);
compile_get_value(double);
compile_get_value(expression_ptr);
} //ns mapnik

View file

@ -230,13 +230,8 @@ def test_map_init_from_string():
map_string = '''<Map background-color="steelblue" base="./" srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"> map_string = '''<Map background-color="steelblue" base="./" srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">
<Style name="My Style"> <Style name="My Style">
<Rule> <Rule>
<PolygonSymbolizer> <PolygonSymbolizer fill="#f2eff9"/>
<CssParameter name="fill">#f2eff9</CssParameter> <LineSymbolizer stroke="rgb(50%,50%,50%)" stroke-width="0.1"/>
</PolygonSymbolizer>
<LineSymbolizer>
<CssParameter name="stroke">rgb(50%,50%,50%)</CssParameter>
<CssParameter name="stroke-width">0.1</CssParameter>
</LineSymbolizer>
</Rule> </Rule>
</Style> </Style>
<Layer name="boundaries"> <Layer name="boundaries">

View file

@ -1,4 +1,4 @@
import math, operator #import math, operator
import Image import Image
import sys import sys
@ -27,6 +27,10 @@ def compare(fn1, fn2):
return -1 return -1
diff = 0 diff = 0
pixels = im1.size[0] * im1.size[1] pixels = im1.size[0] * im1.size[1]
delta_pixels = im2.size[0] * im2.size[1] - pixels
if delta_pixels != 0:
errors.append((fn1, delta_pixels))
return delta_pixels
im1 = im1.getdata() im1 = im1.getdata()
im2 = im2.getdata() im2 = im2.getdata()
for i in range(3, pixels - 1, 3): for i in range(3, pixels - 1, 3):

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Map> <!DOCTYPE Map>
<Map background-color="green" srs="+proj=latlong +datum=WGS84"> <Map background-color="green" srs="+proj=latlong +datum=WGS84" minimum-version="2.0.0">
<Layer name="layer" srs="+proj=latlong +datum=WGS84"> <Layer name="layer" srs="+proj=latlong +datum=WGS84">
<StyleName>My Style</StyleName> <StyleName>My Style</StyleName>

View file

@ -50,7 +50,7 @@ def render(filename, width, height=100):
return m return m
if len(sys.argv) == 2: if len(sys.argv) == 2:
files = [(sys.argv[1], 500)] files = [(sys.argv[1], (500, 500))]
elif len(sys.argv) > 2: elif len(sys.argv) > 2:
files = [sys.argv[1:]] files = [sys.argv[1:]]