Permalink
Browse files

Warn about unused XML elements.

  • Loading branch information...
1 parent 02d8a98 commit f25a2231ff51acf90bd32db5b2710684829d4037 @herm herm committed Mar 12, 2012
@@ -7,7 +7,7 @@
void dump_xml(xml_node const& xml, unsigned level=0)
{
std::string indent;
- int i;
+ unsigned i;
for (i=0; i<level; i++)
{
indent += " ";
@@ -38,7 +38,7 @@ namespace formatting
using boost::property_tree::ptree;
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 (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);
@@ -52,6 +52,7 @@ node_ptr registry::from_xml(xml_node const& xml)
{
std::map<std::string, from_xml_function_ptr>::const_iterator itr = map_.find(xml.name());
if (itr == map_.end()) throw config_error("Unknown element '" + xml.name() + "'", xml);
+ xml.set_processed(true);
return itr->second(xml);
}
} //ns formatting
View
@@ -69,6 +69,7 @@
// stl
#include <iostream>
+#include <sstream>
using boost::lexical_cast;
using boost::bad_lexical_cast;
@@ -117,6 +118,8 @@ class map_parser : boost::noncopyable {
void parse_stroke(stroke & strk, xml_node const & sym);
void ensure_font_face( const std::string & face_name );
+ void find_unused_nodes(xml_node const& root);
+ void find_unused_nodes_recursive(xml_node const& node, std::stringstream &error_text);
std::string ensure_relative_to_xml(boost::optional<std::string> opt_path);
boost::optional<color> get_opt_color_attr(boost::property_tree::ptree const& node,
@@ -323,6 +326,7 @@ void map_parser::parse_map(Map & map, xml_node const& pt, std::string const& bas
{
throw config_error("Not a map file. Node 'Map' not found.");
}
+ find_unused_nodes(pt);
}
void map_parser::parse_map_include(Map & map, xml_node const& include)
@@ -335,41 +339,41 @@ void map_parser::parse_map_include(Map & map, xml_node const& include)
for (; itr != end; ++itr)
{
if (itr->is_text()) continue;
- if (itr->name() == "Include")
+ if (itr->is("Include"))
{
parse_map_include(map, *itr);
}
- else if (itr->name() == "Style")
+ else if (itr->is("Style"))
{
parse_style(map, *itr);
}
- else if (itr->name() == "Layer")
+ else if (itr->is("Layer"))
{
parse_layer(map, *itr);
}
- else if (itr->name() == "FontSet")
+ else if (itr->is("FontSet"))
{
parse_fontset(map, *itr);
}
- else if (itr->name() == "MetaWriter")
+ else if (itr->is("MetaWriter"))
{
parse_metawriter(map, *itr);
}
- else if (itr->name() == "FileSource")
+ else if (itr->is("FileSource"))
{
std::string name = itr->get_attr<std::string>("name");
std::string value = itr->get_text();
file_sources_[name] = value;
}
- else if (itr->name() == "Datasource")
+ else if (itr->is("Datasource"))
{
std::string name = itr->get_attr("name", std::string("Unnamed"));
parameters params;
xml_node::const_iterator paramIter = itr->begin();
xml_node::const_iterator endParam = itr->end();
for (; paramIter != endParam; ++paramIter)
{
- if (paramIter->name() == "Parameter")
+ if (paramIter->is("Parameter"))
{
std::string name = paramIter->get_attr<std::string>("name");
std::string value = paramIter->get_text();
@@ -378,15 +382,15 @@ void map_parser::parse_map_include(Map & map, xml_node const& include)
}
datasource_templates_[name] = params;
}
- else if (itr->name() == "Parameters")
+ else if (itr->is("Parameters"))
{
std::string name = itr->get_attr("name", std::string("Unnamed"));
parameters & params = map.get_extra_parameters();
xml_node::const_iterator paramIter = itr->begin();
xml_node::const_iterator endParam = itr->end();
for (; paramIter != endParam; ++paramIter)
{
- if (paramIter->name() == "Parameter")
+ if (paramIter->is("Parameter"))
{
std::string name = paramIter->get_attr<std::string>("name");
bool is_string = true;
@@ -1525,4 +1529,45 @@ std::string map_parser::ensure_relative_to_xml( boost::optional<std::string> opt
return *opt_path;
}
+void map_parser::find_unused_nodes(xml_node const& root)
+{
+ std::stringstream error_message;
+ find_unused_nodes_recursive(root, error_message);
+ if (!error_message.str().empty())
+ {
+ throw config_error("The following nodes or attributes were not processed while parsing the xml file:" + error_message.str());
+ }
+}
+
+void map_parser::find_unused_nodes_recursive(xml_node const& node, std::stringstream &error_message)
+{
+ if (!node.processed())
+ {
+ if (node.is_text()) {
+ error_message << "\n* text '" << node.text() << "'";
+ } else {
+ error_message << "\n* node '" << node.name() << "' in line " << node.line();
+ }
+ return; //All attributes and children are automatically unprocessed, too.
+ }
+ xml_node::attribute_map const& attr = node.get_attributes();
+ xml_node::attribute_map::const_iterator aitr = attr.begin();
+ xml_node::attribute_map::const_iterator aend = attr.end();
+ for (;aitr!=aend; aitr++)
+ {
+ if (!aitr->second.processed)
+ {
+ error_message << "\n* attribute '" << aitr->first <<
+ "' with value '" << aitr->second.value <<
+ "' in line " << node.line();
+ }
+ }
+ xml_node::const_iterator itr = node.begin();
+ xml_node::const_iterator end = node.end();
+ for (; itr!=end; itr++)
+ {
+ find_unused_nodes_recursive(*itr, error_message);
+ }
+}
+
} // end of namespace mapnik
@@ -98,7 +98,7 @@ text_placements_ptr text_placements_list::from_xml(xml_node const &xml, fontset_
xml_node::const_iterator end = xml.end();
for( ;itr != end; ++itr)
{
- if (itr->is_text() || itr->name() != "Placement") continue;
+ if (itr->is_text() || !itr->is("Placement")) continue;
text_symbolizer_properties &p = list->add();
p.from_xml(*itr, fontsets);
//TODO: if (strict_ &&
View
@@ -165,6 +165,7 @@ xml_tree::xml_tree(std::string const& encoding)
color_grammar(),
expr_grammar(tr_)
{
+ node_.set_processed(true); //root node is always processed
}
void xml_tree::set_filename(std::string fn)
@@ -269,9 +270,13 @@ std::string const& xml_node::name() const
std::string const& xml_node::text() const
{
if (text_node_)
+ {
+ processed_ = true;
return name_;
- else
+ } else
+ {
throw config_error("text() called on non-text node", *this);
+ }
}
std::string const& xml_node::filename() const
@@ -383,7 +388,7 @@ boost::optional<T> xml_node::get_opt_attr(std::string const& name) const
{
throw config_error(std::string("Failed to parse attribute '") +
name + "'. Expected " + name_trait<T>::name() +
- " but got '" + itr->second.value + "'");
+ " but got '" + itr->second.value + "'", *this);
}
return result;
}

0 comments on commit f25a223

Please sign in to comment.