Warn about unused XML elements.

This commit is contained in:
Hermann Kraus 2012-03-12 02:12:58 +01:00
parent 02d8a98b3f
commit f25a2231ff
6 changed files with 66 additions and 15 deletions

View file

@ -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 += " ";

View file

@ -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);

View file

@ -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 file

@ -69,6 +69,7 @@
// stl
#include <iostream>
#include <sstream>
using boost::lexical_cast;
using boost::bad_lexical_cast;
@ -117,6 +118,8 @@ private:
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,33 +339,33 @@ 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;
@ -369,7 +373,7 @@ void map_parser::parse_map_include(Map & map, xml_node const& include)
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,7 +382,7 @@ 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();
@ -386,7 +390,7 @@ void map_parser::parse_map_include(Map & map, xml_node const& include)
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

View file

@ -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 file

@ -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;
}