diff --git a/CHANGELOG b/CHANGELOG index 1d67853ad..dbbe619ad 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,10 @@ For a complete change history, see the SVN log. Mapnik Trunk ------------ +- Print warning if invalid XML property names are used (#110) + +- Made XML property names use consistent dashes, never underscores (#644) + - Added support for drawing only first matching rule using filter-mode="first" in Style (#706) - Added support to PointSymbolizer ('ignore_placement') for skipping adding placed points to collision detector (#564) diff --git a/src/load_map.cpp b/src/load_map.cpp index ed0b09a2b..a082a58fa 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -112,6 +112,7 @@ private: void ensure_font_face( const std::string & face_name ); std::string ensure_relative_to_xml( boost::optional opt_path ); + void ensure_attrs( ptree const& sym, std::string name, std::string attrs); bool strict_; std::string filename_; @@ -170,13 +171,23 @@ void map_parser::parse_map( Map & map, ptree const & pt ) { ptree const & map_node = pt.get_child("Map"); + std::ostringstream s(""); + s << "background-color," + << "background-image," + << "srs," + << "buffer-size," + << "paths-from-xml," + << "minimum-version," + << "font-directory"; + ensure_attrs(map_node, "Map", s.str()); + try { parameters extra_attr; // Check if relative paths should be interpreted as relative to/from XML location // Default is true, and map_parser::ensure_relative_to_xml will be called to modify path - optional paths_from_xml = get_opt_attr(map_node, "paths_from_xml"); + optional paths_from_xml = get_opt_attr(map_node, "paths-from-xml"); if (paths_from_xml) { relative_to_xml_ = *paths_from_xml; @@ -196,24 +207,24 @@ void map_parser::parse_map( Map & map, ptree const & pt ) map.set_srs( get_attr(map_node, "srs", map.srs() )); - optional buffer_size = get_opt_attr(map_node,"buffer_size"); + optional buffer_size = get_opt_attr(map_node,"buffer-size"); if (buffer_size) { map.set_buffer_size(*buffer_size); } - optional font_directory = get_opt_attr(map_node,"font_directory"); + optional font_directory = get_opt_attr(map_node,"font-directory"); if (font_directory) { - extra_attr["font_directory"] = *font_directory; + extra_attr["font-directory"] = *font_directory; freetype_engine::register_fonts( ensure_relative_to_xml(font_directory), false); } - optional min_version_string = get_opt_attr(map_node, "minimum_version"); + optional min_version_string = get_opt_attr(map_node, "minimum-version"); if (min_version_string) { - extra_attr["minimum_version"] = *min_version_string; + extra_attr["minimum-version"] = *min_version_string; boost::char_separator sep("."); boost::tokenizer > tokens(*min_version_string,sep); unsigned i = 0; @@ -341,6 +352,11 @@ void map_parser::parse_map_include( Map & map, ptree const & include ) void map_parser::parse_style( Map & map, ptree const & sty ) { + std::ostringstream s(""); + s << "name," + << "filter-mode"; + ensure_attrs(sty, "Style", s.str()); + string name(""); try { @@ -381,6 +397,7 @@ void map_parser::parse_style( Map & map, ptree const & sty ) void map_parser::parse_metawriter(Map & map, ptree const & pt) { + ensure_attrs(pt, "MetaWriter", "name,type,file,default-output,output-empty"); string name(""); metawriter_ptr writer; try @@ -411,6 +428,7 @@ void map_parser::parse_metawriter(Map & map, ptree const & pt) void map_parser::parse_fontset( Map & map, ptree const & fset ) { + ensure_attrs(fset, "FontSet", "name,Font"); string name(""); try { @@ -452,7 +470,9 @@ void map_parser::parse_fontset( Map & map, ptree const & fset ) void map_parser::parse_font(font_set & fset, ptree const & f) { - std::string face_name = get_attr(f, "face_name", string()); + ensure_attrs(f, "Font", "face-name"); + + std::string face_name = get_attr(f, "face-name", string()); if ( strict_ ) { @@ -465,6 +485,17 @@ void map_parser::parse_font(font_set & fset, ptree const & f) void map_parser::parse_layer( Map & map, ptree const & lay ) { std::string name; + std::ostringstream s(""); + s << "name," + << "srs," + << "status," + << "title," + << "abstract," + << "minzoom," + << "maxzoom," + << "queryable," + << "clear-label-cache"; + ensure_attrs(lay, "Layer", s.str()); try { name = get_attr(lay, "name", string("Unnamed")); @@ -511,7 +542,7 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) } optional clear_cache = - get_opt_attr(lay, "clear_label_cache"); + get_opt_attr(lay, "clear-label-cache"); if (clear_cache) { lyr.set_clear_label_cache( * clear_cache ); @@ -527,11 +558,25 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) if (child.first == "StyleName") { - // TODO check references [DS] - lyr.add_style(child.second.data()); + ensure_attrs(child.second, "StyleName", "none"); + std::string style_name = child.second.data(); + if (style_name.empty()) + { + std::ostringstream ss; + ss << "StyleName is empty in Layer: '" << lyr.name() << "'"; + if (strict_) + throw config_error(ss.str()); + else + std::clog << "### WARNING: " << ss.str() << std::endl; + } + else + { + lyr.add_style(style_name); + } } else if (child.first == "Datasource") { + ensure_attrs(child.second, "Datasource", "base"); parameters params; optional base = get_opt_attr( child.second, "base" ); if( base ) @@ -549,6 +594,7 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) if (paramIter->first == "Parameter") { + ensure_attrs(param, "Parameter", "name"); std::string name = get_attr(param, "name"); std::string value = get_value( param, "datasource parameter"); @@ -623,6 +669,7 @@ void map_parser::parse_layer( Map & map, ptree const & lay ) void map_parser::parse_rule( feature_type_style & style, ptree const & r ) { + ensure_attrs(r, "Rule", "name,title"); std::string name; try { @@ -749,12 +796,14 @@ void map_parser::parse_point_symbolizer( rule & rule, ptree const & sym ) { try { + std::stringstream s; + s << "file,base,allow-overlap,ignore-placement,opacity,placement,meta-writer,meta-output"; optional file = get_opt_attr(sym, "file"); optional base = get_opt_attr(sym, "base"); optional allow_overlap = - get_opt_attr(sym, "allow_overlap"); + get_opt_attr(sym, "allow-overlap"); optional ignore_placement = - get_opt_attr(sym, "ignore_placement"); + get_opt_attr(sym, "ignore-placement"); optional opacity = get_opt_attr(sym, "opacity"); @@ -762,6 +811,8 @@ void map_parser::parse_point_symbolizer( rule & rule, ptree const & sym ) if (file) { + s << "base,transform"; + ensure_attrs(sym, "PointSymbolizer", s.str()); try { if( base ) @@ -799,7 +850,8 @@ void map_parser::parse_point_symbolizer( rule & rule, ptree const & sym ) if (!mapnik::svg::parse_transform(*transform_wkt,tr)) { std::stringstream ss; - ss << "Could not parse transform from '" << transform_wkt << "', expected string like: 'matrix(1, 0, 0, 1, 0, 0)'"; + ss << "Could not parse transform from '" << transform_wkt + << "', expected string like: 'matrix(1, 0, 0, 1, 0, 0)'"; if (strict_) throw config_error(ss.str()); // value_error here? else @@ -830,6 +882,8 @@ void map_parser::parse_point_symbolizer( rule & rule, ptree const & sym ) } else { + // transform not supported + ensure_attrs(sym, "PointSymbolizer", s.str()); point_symbolizer symbol; if (allow_overlap) @@ -868,9 +922,20 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) optional file = get_opt_attr(sym, "file"); optional base = get_opt_attr(sym, "base"); optional transform_wkt = get_opt_attr(sym, "transform"); - + + std::stringstream s; + //s << "file,opacity,spacing,max-error,allow-overlap,placement,"; + s << "file,base,transform,fill,opacity," + << "spacing,max-error,allow-overlap," + << "width,height,placement,marker-type," + << "meta-writer,meta-output," + << "stroke,stroke-width,stroke-opacity,stroke-linejoin," + << "stroke-linecap,stroke-gamma,stroke-dashoffet,stroke-dasharray"; + if (file) { + //s << "base,transform"; + //ensure_attrs(sym, "MarkersSymbolizer", s.str()); try { if (base) @@ -897,6 +962,11 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) } } } + /*else + { + //s << "fill,marker-type,width,height"; + //ensure_attrs(sym, "MarkersSymbolizer", s.str()); + }*/ markers_symbolizer symbol(parse_path(filename)); optional opacity = get_opt_attr(sym, "opacity"); @@ -908,7 +978,8 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) if (!mapnik::svg::parse_transform(*transform_wkt,tr)) { std::stringstream ss; - ss << "Could not parse transform from '" << transform_wkt << "', expected string like: 'matrix(1, 0, 0, 1, 0, 0)'"; + ss << "Could not parse transform from '" << transform_wkt + << "', expected string like: 'matrix(1, 0, 0, 1, 0, 0)'"; if (strict_) throw config_error(ss.str()); // value_error here? else @@ -923,9 +994,9 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) if (c) symbol.set_fill(*c); optional spacing = get_opt_attr(sym, "spacing"); if (spacing) symbol.set_spacing(*spacing); - optional max_error = get_opt_attr(sym, "max_error"); + optional max_error = get_opt_attr(sym, "max-error"); if (max_error) symbol.set_max_error(*max_error); - optional allow_overlap = get_opt_attr(sym, "allow_overlap"); + optional allow_overlap = get_opt_attr(sym, "allow-overlap"); if (allow_overlap) symbol.set_allow_overlap(*allow_overlap); optional w = get_opt_attr(sym, "width"); @@ -959,7 +1030,7 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) if (placement == MARKER_POINT_PLACEMENT) dfl_marker_type = ELLIPSE; - marker_type_e marker_type = get_attr(sym, "marker_type", dfl_marker_type); + marker_type_e marker_type = get_attr(sym, "marker-type", dfl_marker_type); symbol.set_marker_type( marker_type ); parse_metawriter_in_symbolizer(symbol, sym); @@ -974,6 +1045,7 @@ void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym ) void map_parser::parse_line_pattern_symbolizer( rule & rule, ptree const & sym ) { + ensure_attrs(sym, "LinePatternSymbolizer", "file,base,meta-writer,meta-output"); try { std::string file = get_attr(sym, "file"); @@ -1021,6 +1093,7 @@ void map_parser::parse_line_pattern_symbolizer( rule & rule, ptree const & sym ) void map_parser::parse_polygon_pattern_symbolizer( rule & rule, ptree const & sym ) { + ensure_attrs(sym, "PolygonPatternSymbolizer", "file,base,alignment,meta-writer,meta-output"); try { std::string file = get_attr(sym, "file"); @@ -1071,15 +1144,27 @@ void map_parser::parse_polygon_pattern_symbolizer( rule & rule, void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) { + std::stringstream s; + s << "name,face-name,fontset-name,size,fill,orientation," + << "dx,dy,placement,vertical-alignment,halo-fill," + << "halo-radius,text-ratio,wrap-width,wrap-before," + << "wrap-character,text-transform,line-spacing," + << "label-position-tolerance,character-spacing," + << "spacing,minimum-distance,minimum-padding," + << "avoid-edges,allow-overlap,opacity,max-char-angle-delta," + << "horizontal-alignment,justify-alignment," + << "meta-writer,meta-output"; + + ensure_attrs(sym, "TextSymbolizer", s.str()); try { std::string name = get_attr(sym, "name"); optional face_name = - get_opt_attr(sym, "face_name"); + get_opt_attr(sym, "face-name"); optional fontset_name = - get_opt_attr(sym, "fontset_name"); + get_opt_attr(sym, "fontset-name"); unsigned size = get_attr(sym, "size", 10U); @@ -1141,17 +1226,17 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) default_vertical_alignment = TOP; } - vertical_alignment_e valign = get_attr(sym, "vertical_alignment", default_vertical_alignment); + vertical_alignment_e valign = get_attr(sym, "vertical-alignment", default_vertical_alignment); text_symbol.set_vertical_alignment(valign); // halo fill and radius - optional halo_fill = get_opt_attr(sym, "halo_fill"); + optional halo_fill = get_opt_attr(sym, "halo-fill"); if (halo_fill) { text_symbol.set_halo_fill( * halo_fill ); } optional halo_radius = - get_opt_attr(sym, "halo_radius"); + get_opt_attr(sym, "halo-radius"); if (halo_radius) { text_symbol.set_halo_radius(*halo_radius); @@ -1159,21 +1244,21 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) // text ratio and wrap width optional text_ratio = - get_opt_attr(sym, "text_ratio"); + get_opt_attr(sym, "text-ratio"); if (text_ratio) { text_symbol.set_text_ratio(*text_ratio); } optional wrap_width = - get_opt_attr(sym, "wrap_width"); + get_opt_attr(sym, "wrap-width"); if (wrap_width) { text_symbol.set_wrap_width(*wrap_width); } optional wrap_before = - get_opt_attr(sym, "wrap_before"); + get_opt_attr(sym, "wrap-before"); if (wrap_before) { text_symbol.set_wrap_before(*wrap_before); @@ -1181,7 +1266,7 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) // character used to break long strings optional wrap_char = - get_opt_attr(sym, "wrap_character"); + get_opt_attr(sym, "wrap-character"); if (wrap_char && (*wrap_char).size() > 0) { text_symbol.set_wrap_char((*wrap_char)[0]); @@ -1189,25 +1274,25 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) // text conversion before rendering text_transform_e tconvert = - get_attr(sym, "text_transform", NONE); + get_attr(sym, "text-transform", NONE); text_symbol.set_text_transform(tconvert); // spacing between text lines - optional line_spacing = get_opt_attr(sym, "line_spacing"); + optional line_spacing = get_opt_attr(sym, "line-spacing"); if (line_spacing) { text_symbol.set_line_spacing(*line_spacing); } // tolerance between label spacing along line - optional label_position_tolerance = get_opt_attr(sym, "label_position_tolerance"); + optional label_position_tolerance = get_opt_attr(sym, "label-position-tolerance"); if (label_position_tolerance) { text_symbol.set_label_position_tolerance(*label_position_tolerance); } // spacing between characters in text - optional character_spacing = get_opt_attr(sym, "character_spacing"); + optional character_spacing = get_opt_attr(sym, "character-spacing"); if (character_spacing) { text_symbol.set_character_spacing(*character_spacing); @@ -1221,16 +1306,14 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) } // minimum distance between labels - optional min_distance = - get_opt_attr(sym, "minimum_distance"); + optional min_distance = get_opt_attr(sym, "minimum-distance"); if (min_distance) { text_symbol.set_minimum_distance(*min_distance); } // minimum distance from edge of the map - optional min_padding = - get_opt_attr(sym, "minimum_padding"); + optional min_padding = get_opt_attr(sym, "minimum-padding"); if (min_padding) { text_symbol.set_minimum_padding(*min_padding); @@ -1238,7 +1321,7 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) // do not render labels around edges optional avoid_edges = - get_opt_attr(sym, "avoid_edges"); + get_opt_attr(sym, "avoid-edges"); if (avoid_edges) { text_symbol.set_avoid_edges( * avoid_edges); @@ -1246,7 +1329,7 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) // allow_overlap optional allow_overlap = - get_opt_attr(sym, "allow_overlap"); + get_opt_attr(sym, "allow-overlap"); if (allow_overlap) { text_symbol.set_allow_overlap( * allow_overlap ); @@ -1262,18 +1345,18 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) // max_char_angle_delta optional max_char_angle_delta = - get_opt_attr(sym, "max_char_angle_delta"); + get_opt_attr(sym, "max-char-angle-delta"); if (max_char_angle_delta) { text_symbol.set_max_char_angle_delta( (*max_char_angle_delta)*(M_PI/180)); } // horizontal alignment - horizontal_alignment_e halign = get_attr(sym, "horizontal_alignment", H_MIDDLE); + horizontal_alignment_e halign = get_attr(sym, "horizontal-alignment", H_MIDDLE); text_symbol.set_horizontal_alignment(halign); // justify alignment - justify_alignment_e jalign = get_attr(sym, "justify_alignment", J_MIDDLE); + justify_alignment_e jalign = get_attr(sym, "justify-alignment", J_MIDDLE); text_symbol.set_justify_alignment(jalign); parse_metawriter_in_symbolizer(text_symbol, sym); @@ -1288,15 +1371,33 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym ) void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) { + + std::stringstream s; + //std::string a[] = {"a","b"}; + s << "name,face-name,fontset-name,size,fill," + << "dx,dy,placement,vertical-alignment,halo-fill," + << "halo-radius,text-ratio,wrap-width,wrap-before," + << "wrap-character,text-transform,line-spacing," + << "label-position-tolerance,character-spacing," + << "spacing,minimum-distance,minimum-padding," + << "avoid-edges,allow-overlap,opacity,max-char-angle-delta," + << "horizontal-alignment,justify-alignment," + // additional for shield + /* transform instead of orientation */ + << "file,transform,shield-dx,shield-dy," + << "text-opacity,unlock-image,no-text," + << "meta-writer,meta-output"; + + ensure_attrs(sym, "ShieldSymbolizer", s.str()); try { std::string name = get_attr(sym, "name"); optional face_name = - get_opt_attr(sym, "face_name"); + get_opt_attr(sym, "face-name"); optional fontset_name = - get_opt_attr(sym, "fontset_name"); + get_opt_attr(sym, "fontset-name"); unsigned size = get_attr(sym, "size", 10U); color fill = get_attr(sym, "fill", color(0,0,0)); @@ -1322,7 +1423,7 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) if (fontset_name && face_name) { - throw config_error(std::string("Can't have both face_name and fontset_name")); + throw config_error(std::string("Can't have both face-name and fontset-name")); } else if (fontset_name) { @@ -1346,15 +1447,15 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) } else { - throw config_error(std::string("Must have face_name or fontset_name")); + throw config_error(std::string("Must have face-name or fontset-name")); } // text displacement (relative to shield_displacement) double dx = get_attr(sym, "dx", 0.0); double dy = get_attr(sym, "dy", 0.0); shield_symbol.set_displacement(dx,dy); // shield displacement - double shield_dx = get_attr(sym, "shield_dx", 0.0); - double shield_dy = get_attr(sym, "shield_dy", 0.0); + double shield_dx = get_attr(sym, "shield-dx", 0.0); + double shield_dy = get_attr(sym, "shield-dy", 0.0); shield_symbol.set_shield_displacement(shield_dx,shield_dy); label_placement_e placement = @@ -1363,36 +1464,34 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) // don't render shields around edges optional avoid_edges = - get_opt_attr(sym, "avoid_edges"); + get_opt_attr(sym, "avoid-edges"); if (avoid_edges) { shield_symbol.set_avoid_edges( *avoid_edges); } // halo fill and radius - optional halo_fill = get_opt_attr(sym, "halo_fill"); + optional halo_fill = get_opt_attr(sym, "halo-fill"); if (halo_fill) { shield_symbol.set_halo_fill( * halo_fill ); } optional halo_radius = - get_opt_attr(sym, "halo_radius"); + get_opt_attr(sym, "halo-radius"); if (halo_radius) { shield_symbol.set_halo_radius(*halo_radius); } // minimum distance between labels - optional min_distance = - get_opt_attr(sym, "minimum_distance"); + optional min_distance = get_opt_attr(sym, "minimum-distance"); if (min_distance) { shield_symbol.set_minimum_distance(*min_distance); } // minimum distance from edge of the map - optional min_padding = - get_opt_attr(sym, "minimum_padding"); + optional min_padding = get_opt_attr(sym, "minimum-padding"); if (min_padding) { shield_symbol.set_minimum_padding(*min_padding); @@ -1407,33 +1506,33 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) // allow_overlap optional allow_overlap = - get_opt_attr(sym, "allow_overlap"); + get_opt_attr(sym, "allow-overlap"); if (allow_overlap) { shield_symbol.set_allow_overlap( * allow_overlap ); } // vertical alignment - vertical_alignment_e valign = get_attr(sym, "vertical_alignment", MIDDLE); + vertical_alignment_e valign = get_attr(sym, "vertical-alignment", MIDDLE); shield_symbol.set_vertical_alignment(valign); // horizontal alignment - horizontal_alignment_e halign = get_attr(sym, "horizontal_alignment", H_MIDDLE); + horizontal_alignment_e halign = get_attr(sym, "horizontal-alignment", H_MIDDLE); shield_symbol.set_horizontal_alignment(halign); // justify alignment - justify_alignment_e jalign = get_attr(sym, "justify_alignment", J_MIDDLE); + justify_alignment_e jalign = get_attr(sym, "justify-alignment", J_MIDDLE); shield_symbol.set_justify_alignment(jalign); optional wrap_width = - get_opt_attr(sym, "wrap_width"); + get_opt_attr(sym, "wrap-width"); if (wrap_width) { shield_symbol.set_wrap_width(*wrap_width); } optional wrap_before = - get_opt_attr(sym, "wrap_before"); + get_opt_attr(sym, "wrap-before"); if (wrap_before) { shield_symbol.set_wrap_before(*wrap_before); @@ -1441,7 +1540,7 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) // character used to break long strings optional wrap_char = - get_opt_attr(sym, "wrap_character"); + get_opt_attr(sym, "wrap-character"); if (wrap_char && (*wrap_char).size() > 0) { shield_symbol.set_wrap_char((*wrap_char)[0]); @@ -1449,18 +1548,18 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) // text conversion before rendering text_transform_e tconvert = - get_attr(sym, "text_transform", NONE); + get_attr(sym, "text-transform", NONE); shield_symbol.set_text_transform(tconvert); // spacing between text lines - optional line_spacing = get_opt_attr(sym, "line_spacing"); + optional line_spacing = get_opt_attr(sym, "line-spacing"); if (line_spacing) { shield_symbol.set_line_spacing(*line_spacing); } // spacing between characters in text - optional character_spacing = get_opt_attr(sym, "character_spacing"); + optional character_spacing = get_opt_attr(sym, "character-spacing"); if (character_spacing) { shield_symbol.set_character_spacing(*character_spacing); @@ -1501,7 +1600,7 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) // unlock_image optional unlock_image = - get_opt_attr(sym, "unlock_image"); + get_opt_attr(sym, "unlock-image"); if (unlock_image) { shield_symbol.set_unlock_image( * unlock_image ); @@ -1509,7 +1608,7 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym ) // no text optional no_text = - get_opt_attr(sym, "no_text"); + get_opt_attr(sym, "no-text"); if (no_text) { shield_symbol.set_no_text( * no_text ); @@ -1606,6 +1705,11 @@ void map_parser::parse_stroke(stroke & strk, ptree const & sym) void map_parser::parse_line_symbolizer( rule & rule, ptree const & sym ) { + std::stringstream s; + s << "meta-writer,meta-output," + << "stroke,stroke-width,stroke-opacity,stroke-linejoin," + << "stroke-linecap,stroke-gamma,stroke-dashoffet,stroke-dasharray"; + ensure_attrs(sym, "LineSymbolizer", s.str()); try { stroke strk; @@ -1625,6 +1729,7 @@ void map_parser::parse_line_symbolizer( rule & rule, ptree const & sym ) void map_parser::parse_polygon_symbolizer( rule & rule, ptree const & sym ) { + ensure_attrs(sym, "PolygonSymbolizer", "fill,fill-opacity,gamma,meta-writer,meta-output"); try { polygon_symbolizer poly_sym; @@ -1651,7 +1756,9 @@ void map_parser::parse_polygon_symbolizer( rule & rule, ptree const & sym ) void map_parser::parse_building_symbolizer( rule & rule, ptree const & sym ) { - try { + ensure_attrs(sym, "PolygonSymbolizer", "fill,fill-opacity,height,meta-writer,meta-output"); + try + { building_symbolizer building_sym; // fill @@ -1661,6 +1768,7 @@ void map_parser::parse_building_symbolizer( rule & rule, ptree const & sym ) optional opacity = get_opt_attr(sym, "fill-opacity"); if (opacity) building_sym.set_opacity(*opacity); // height + // TODO - expression optional height = get_opt_attr(sym, "height"); if (height) building_sym.set_height(*height); @@ -1676,6 +1784,8 @@ void map_parser::parse_building_symbolizer( rule & rule, ptree const & sym ) void map_parser::parse_raster_symbolizer( rule & rule, ptree const & sym ) { + // no support for meta-writer,meta-output + ensure_attrs(sym, "PolygonSymbolizer", "mode,scaling,opacity,filter-factory"); try { raster_symbolizer raster_sym; @@ -1693,7 +1803,7 @@ void map_parser::parse_raster_symbolizer( rule & rule, ptree const & sym ) if (opacity) raster_sym.set_opacity(*opacity); // filter factor - optional filter_factor = get_opt_attr(sym, "filter_factor"); + optional filter_factor = get_opt_attr(sym, "filter-factor"); if (filter_factor) raster_sym.set_filter_factor(*filter_factor); ptree::const_iterator cssIter = sym.begin(); @@ -1726,12 +1836,13 @@ void map_parser::parse_raster_symbolizer( rule & rule, ptree const & sym ) } } -void map_parser::parse_glyph_symbolizer(rule & rule, ptree const &sym) +void map_parser::parse_glyph_symbolizer(rule & rule, ptree const & sym) { + ensure_attrs(sym, "GlyphSymbolizer", "face-name,char,angle,angle-mode,value,size,color,halo-fill,halo-radius,allow-overlap,avoid-edges,dx,dy,meta-writer,meta-output"); try { // Parse required constructor args - std::string face_name = get_attr(sym, "face_name"); + std::string face_name = get_attr(sym, "face-name"); std::string _char = get_attr(sym, "char"); glyph_symbolizer glyph_sym = glyph_symbolizer( @@ -1750,7 +1861,7 @@ void map_parser::parse_glyph_symbolizer(rule & rule, ptree const &sym) glyph_sym.set_angle(parse_expression(*angle, "utf8")); angle_mode_e angle_mode = - get_attr(sym, "angle_mode", TRIGONOMETRIC); + get_attr(sym, "angle-mode", TRIGONOMETRIC); glyph_sym.set_angle_mode(angle_mode); // value @@ -1771,21 +1882,21 @@ void map_parser::parse_glyph_symbolizer(rule & rule, ptree const &sym) glyph_sym.set_color(parse_expression(*_color, "utf8")); // halo_fill - optional halo_fill = get_opt_attr(sym, "halo_fill"); + optional halo_fill = get_opt_attr(sym, "halo-fill"); if (halo_fill) glyph_sym.set_halo_fill(*halo_fill); // halo_radius optional halo_radius = get_opt_attr( sym, - "halo_radius"); + "halo-radius"); if (halo_radius) glyph_sym.set_halo_radius(*halo_radius); // allow_overlap optional allow_overlap = get_opt_attr( sym, - "allow_overlap" + "allow-overlap" ); if (allow_overlap) glyph_sym.set_allow_overlap(*allow_overlap); @@ -1793,7 +1904,7 @@ void map_parser::parse_glyph_symbolizer(rule & rule, ptree const &sym) // avoid_edges optional avoid_edges = get_opt_attr( sym, - "avoid_edges" + "avoid-edges" ); if (avoid_edges) glyph_sym.set_avoid_edges(*avoid_edges); @@ -1851,6 +1962,7 @@ void map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc, if (cb_tag.first == "ColorBand") { + ensure_attrs(cb, "ColorBand", "value,color,midpoints,max-value,label"); std::string value_s = get_attr(cb, "value"); float value; std::stringstream(value_s) >> value; @@ -1859,7 +1971,7 @@ void map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc, throw config_error("missing color"); } unsigned midpoints = get_attr(cb, "midpoints", 0); - optional max_value = get_opt_attr(cb, "max_value"); + optional max_value = get_opt_attr(cb, "max-value"); if (max_value) { rc->append_band(value, *max_value, *c, midpoints); } else { @@ -1915,4 +2027,45 @@ std::string map_parser::ensure_relative_to_xml( boost::optional opt return *opt_path; } +void map_parser::ensure_attrs(ptree const& sym, std::string name, std::string attrs) +{ + + typedef ptree::key_type::value_type Ch; + //typedef boost::property_tree::xml_parser::xmlattr x_att; + + std::set attr_set; + boost::split(attr_set, attrs, boost::is_any_of(",")); + for (ptree::const_iterator itr = sym.begin(); itr != sym.end(); ++itr) + { + //ptree::value_type const& v = *itr; + if (itr->first == boost::property_tree::xml_parser::xmlattr()) + { + optional attribs = sym.get_child_optional( boost::property_tree::xml_parser::xmlattr() ); + if (attribs) + { + std::ostringstream s(""); + s << "### " << name << " properties warning: "; + int missing = 0; + for (ptree::const_iterator it = attribs.get().begin(); it != attribs.get().end(); ++it) + { + std::string name = it->first; + bool found = (attr_set.find(name) != attr_set.end()); + if (!found) + { + if (missing) s << ","; + s << "'" << name << "'"; + ++missing; + } + } + if (missing) { + if (missing > 1) s << " are"; + else s << " is"; + s << " invalid, acceptable values are:\n'" << attrs << "'\n"; + std::clog << s.str(); + } + } + } + } +} + } // end of namespace mapnik