2012-03-05 16:49:54 +01:00
/*****************************************************************************
*
* 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-03-06 15:18:11 +01:00
//mapnik
2012-03-05 16:49:54 +01:00
# include <mapnik/xml_tree.hpp>
2012-03-06 15:18:11 +01:00
# include <mapnik/util/conversions.hpp>
# include <mapnik/enumeration.hpp>
2012-03-06 15:47:08 +01:00
# include <mapnik/color_factory.hpp>
2012-03-07 03:57:31 +01:00
# include <mapnik/gamma_method.hpp>
# include <mapnik/line_symbolizer.hpp>
2012-03-07 19:16:41 +01:00
# include <mapnik/feature_type_style.hpp>
# include <mapnik/text_properties.hpp>
2012-03-12 01:09:26 +01:00
# include <mapnik/config_error.hpp>
2012-03-06 15:18:11 +01:00
//boost
# include <boost/lexical_cast.hpp>
2012-03-05 16:49:54 +01:00
namespace mapnik
{
2012-03-06 15:18:11 +01:00
template < typename T >
inline boost : : optional < T > fast_cast ( xml_tree const & tree , std : : string const & value )
{
2012-03-13 11:11:28 +01:00
try
{
return boost : : lexical_cast < T > ( value ) ;
}
catch ( boost : : bad_lexical_cast const & ex )
{
return boost : : optional < T > ( ) ;
}
2012-03-06 15:18:11 +01:00
}
template < >
inline boost : : optional < int > fast_cast ( xml_tree const & tree , std : : string const & value )
{
int result ;
2012-03-23 12:01:18 +01:00
if ( mapnik : : util : : string2int ( value , result ) )
2012-03-06 15:18:11 +01:00
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 ;
2012-03-23 12:01:18 +01:00
if ( mapnik : : util : : string2double ( value , result ) )
2012-03-06 15:18:11 +01:00
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 ;
2012-03-23 12:01:18 +01:00
if ( mapnik : : util : : string2float ( value , result ) )
2012-03-06 15:18:11 +01:00
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 ;
}
2012-03-06 15:47:08 +01:00
template < >
inline boost : : optional < color > fast_cast ( xml_tree const & tree , std : : string const & value )
{
2012-03-11 23:24:28 +01:00
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 + " ' " ) ;
}
2012-03-06 15:47:08 +01:00
}
2012-03-07 19:16:41 +01:00
template < >
inline boost : : optional < expression_ptr > fast_cast ( xml_tree const & tree , std : : string const & value )
{
2012-03-11 23:24:28 +01:00
expression_ptr expr ( boost : : make_shared < expr_node > ( true ) ) ;
if ( expression_factory : : parse_from_string ( expr , value , tree . expr_grammar ) )
{
return expr ;
2012-04-06 20:42:36 +02:00
}
else
2012-03-11 23:24:28 +01:00
{
throw mapnik : : config_error ( " Failed to parse expression ' " + value + " ' " ) ;
}
2012-03-07 19:16:41 +01:00
}
2012-03-06 15:18:11 +01:00
/****************************************************************************/
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 ) ;
} ;
2012-03-13 15:56:11 +01:00
# define DEFINE_NAME_TRAIT( type, type_name ) \
2012-03-06 15:18:11 +01:00
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 " )
2012-03-07 19:16:41 +01:00
DEFINE_NAME_TRAIT ( expression_ptr , " expression_ptr " )
2012-03-06 15:18:11 +01:00
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 ;
}
} ;
/****************************************************************************/
2012-03-11 23:24:28 +01:00
xml_tree : : xml_tree ( std : : string const & encoding )
: node_ ( * this , " <root> " ) ,
file_ ( ) ,
tr_ ( encoding ) ,
color_grammar ( ) ,
2012-04-07 01:50:11 +02:00
expr_grammar ( tr_ ) ,
2012-05-27 23:50:09 +02:00
path_expr_grammar ( ) ,
transform_expr_grammar ( expr_grammar )
2012-03-05 16:49:54 +01:00
{
2012-03-12 02:12:58 +01:00
node_ . set_processed ( true ) ; //root node is always processed
2012-03-05 16:49:54 +01:00
}
void xml_tree : : set_filename ( std : : string fn )
{
file_ = fn ;
}
2012-03-12 01:09:26 +01:00
std : : string const & xml_tree : : filename ( ) const
2012-03-05 16:49:54 +01:00
{
return file_ ;
}
2012-03-06 15:18:11 +01:00
xml_node & xml_tree : : root ( )
2012-03-05 16:49:54 +01:00
{
return node_ ;
}
2012-03-07 03:57:31 +01:00
/****************************************************************************/
xml_attribute : : xml_attribute ( std : : string const & value_ )
: value ( value_ ) , processed ( false )
{
}
/****************************************************************************/
2012-04-06 21:58:08 +02:00
node_not_found : : node_not_found ( std : : string const & node_name )
2012-03-07 03:57:31 +01:00
: 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 )
:
2012-03-13 15:56:11 +01:00
node_name_ ( node_name ) ,
attribute_name_ ( attribute_name )
2012-03-07 03:57:31 +01:00
{
}
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 ( )
{
}
2012-03-05 16:49:54 +01:00
/****************************************************************************/
2012-04-06 21:58:08 +02:00
xml_node : : xml_node ( xml_tree & tree , std : : string const & name , unsigned line , bool text_node )
2012-03-05 16:49:54 +01:00
: tree_ ( tree ) ,
name_ ( name ) ,
text_node_ ( text_node ) ,
line_ ( line ) ,
processed_ ( false )
{
}
2012-03-12 01:09:26 +01:00
std : : string xml_node : : xml_text = " <xmltext> " ;
std : : string const & xml_node : : name ( ) const
2012-03-05 16:49:54 +01:00
{
if ( ! text_node_ )
return name_ ;
else
2012-03-12 01:09:26 +01:00
return xml_text ;
2012-03-05 16:49:54 +01:00
}
2012-03-12 01:09:26 +01:00
std : : string const & xml_node : : text ( ) const
2012-03-05 16:49:54 +01:00
{
if ( text_node_ )
2012-03-12 02:12:58 +01:00
{
processed_ = true ;
2012-03-05 16:49:54 +01:00
return name_ ;
2012-03-12 02:12:58 +01:00
} else
{
2012-03-12 01:09:26 +01:00
throw config_error ( " text() called on non - text node " , *this) ;
2012-03-12 02:12:58 +01:00
}
2012-03-12 01:09:26 +01:00
}
std : : string const & xml_node : : filename ( ) const
{
return tree_ . filename ( ) ;
2012-03-05 16:49:54 +01:00
}
2012-03-07 03:57:31 +01:00
bool xml_node : : is_text ( ) const
2012-03-05 16:49:54 +01:00
{
2012-03-07 03:57:31 +01:00
return text_node_ ;
}
bool xml_node : : is ( std : : string const & name ) const
{
if ( name_ = = name )
{
processed_ = true ;
return true ;
}
return false ;
2012-03-05 16:49:54 +01:00
}
2012-03-07 01:35:37 +01:00
xml_node & xml_node : : add_child ( std : : string const & name , unsigned line , bool text_node )
2012-03-05 16:49:54 +01:00
{
children_ . push_back ( xml_node ( tree_ , name , line , text_node ) ) ;
return children_ . back ( ) ;
}
2012-03-07 03:57:31 +01:00
void xml_node : : add_attribute ( std : : string const & name , std : : string const & value )
{
attributes_ . insert ( std : : make_pair ( name , xml_attribute ( value ) ) ) ;
}
2012-03-08 01:29:19 +01:00
xml_node : : attribute_map const & xml_node : : get_attributes ( ) const
{
return attributes_ ;
}
2012-03-07 03:57:31 +01:00
void xml_node : : set_processed ( bool processed ) const
{
processed_ = processed ;
}
2012-03-08 18:51:23 +01:00
bool xml_node : : processed ( ) const
{
return processed_ ;
}
2012-03-07 03:57:31 +01:00
xml_node : : const_iterator xml_node : : begin ( ) const
{
return children_ . begin ( ) ;
}
xml_node : : const_iterator xml_node : : end ( ) const
{
return children_ . end ( ) ;
}
2012-03-07 02:23:16 +01:00
xml_node & xml_node : : get_child ( std : : string const & name )
2012-03-06 15:18:11 +01:00
{
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 ) ;
}
2012-03-07 03:57:31 +01:00
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 ;
}
2012-03-06 15:18:11 +01:00
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 > ( ) ;
2012-03-07 03:57:31 +01:00
itr - > second . processed = true ;
boost : : optional < T > result = fast_cast < T > ( tree_ , itr - > second . value ) ;
2012-03-06 15:18:11 +01:00
if ( ! result )
{
throw config_error ( std : : string ( " Failed to parse attribute ' " ) +
name + " '. Expected " + name_trait < T > : : name ( ) +
2012-03-12 02:12:58 +01:00
" but got ' " + itr - > second . value + " ' " , * this ) ;
2012-03-07 03:57:31 +01:00
}
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
{
2012-03-07 19:16:41 +01:00
boost : : optional < T > result = fast_cast < T > ( tree_ , get_text ( ) ) ;
2012-03-07 03:57:31 +01:00
if ( ! result )
{
2012-03-12 01:09:26 +01:00
throw config_error ( std : : string ( " Failed to parse value. Expected " )
+ name_trait < T > : : name ( ) +
" but got ' " + get_text ( ) + " ' " , * this ) ;
2012-03-06 15:18:11 +01:00
}
2012-03-07 19:16:41 +01:00
return * result ;
2012-03-06 15:18:11 +01:00
}
2012-03-08 18:51:23 +01:00
unsigned xml_node : : line ( ) const
{
return line_ ;
}
2012-03-07 03:57:31 +01:00
# define compile_get_opt_attr(T) template boost::optional<T> xml_node::get_opt_attr<T>(std::string const&) const
2012-03-07 19:16:41 +01:00
# 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
2012-03-05 16:49:54 +01:00
2012-03-07 19:16:41 +01:00
compile_get_opt_attr ( boolean ) ;
2012-03-07 03:57:31 +01:00
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 ) ;
2012-03-07 19:16:41 +01:00
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 ) ;
2012-03-11 23:24:28 +01:00
compile_get_opt_attr ( expression_ptr ) ;
2012-03-07 19:16:41 +01:00
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 ) ;
2012-05-12 02:40:21 +02:00
compile_get_attr ( line_rasterizer_e ) ;
2012-03-07 19:16:41 +01:00
compile_get_attr ( colorizer_mode ) ;
compile_get_attr ( double ) ;
compile_get_value ( int ) ;
compile_get_value ( double ) ;
compile_get_value ( expression_ptr ) ;
2012-03-05 16:49:54 +01:00
} //ns mapnik