diff --git a/include/mapnik/xml_loader.hpp b/include/mapnik/xml_loader.hpp index 2bc8f4af3..1991fa685 100644 --- a/include/mapnik/xml_loader.hpp +++ b/include/mapnik/xml_loader.hpp @@ -23,14 +23,17 @@ #ifndef MAPNIK_LIBXML2_LOADER_HPP #define MAPNIK_LIBXML2_LOADER_HPP +// mapnik +#include // for MAPNIK_DECL + // stl #include namespace mapnik { -class xml_node; -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=""); +class MAPNIK_DECL xml_node; +MAPNIK_DECL void read_xml(std::string const & filename, xml_node &node); +MAPNIK_DECL void read_xml_string(std::string const & str, xml_node &node, std::string const & base_path=""); } #endif // MAPNIK_LIBXML2_LOADER_HPP diff --git a/include/mapnik/xml_node.hpp b/include/mapnik/xml_node.hpp index 28be9ff0c..106bbc673 100644 --- a/include/mapnik/xml_node.hpp +++ b/include/mapnik/xml_node.hpp @@ -23,6 +23,9 @@ #ifndef MAPNIK_XML_NODE_H #define MAPNIK_XML_NODE_H +//mapnik +#include // for MAPNIK_DECL + //boost #include @@ -34,9 +37,9 @@ namespace mapnik { -class xml_tree; +class MAPNIK_DECL xml_tree; -class xml_attribute +class MAPNIK_DECL xml_attribute { public: xml_attribute(const char * value_); @@ -44,7 +47,7 @@ public: mutable bool processed; }; -class node_not_found: public std::exception +class MAPNIK_DECL node_not_found: public std::exception { public: node_not_found(std::string const& node_name); @@ -56,7 +59,7 @@ protected: mutable std::string msg_; }; -class attribute_not_found: public std::exception +class MAPNIK_DECL attribute_not_found: public std::exception { public: attribute_not_found(std::string const& node_name, std::string const& attribute_name); @@ -69,7 +72,7 @@ protected: mutable std::string msg_; }; -class more_than_one_child: public std::exception +class MAPNIK_DECL more_than_one_child: public std::exception { public: more_than_one_child(std::string const& node_name); @@ -81,7 +84,7 @@ protected: mutable std::string msg_; }; -class xml_node +class MAPNIK_DECL xml_node { public: using const_iterator = std::list::const_iterator; diff --git a/include/mapnik/xml_tree.hpp b/include/mapnik/xml_tree.hpp index 9cb29a8cc..f13cd4170 100644 --- a/include/mapnik/xml_tree.hpp +++ b/include/mapnik/xml_tree.hpp @@ -33,7 +33,7 @@ namespace mapnik { -class xml_tree +class MAPNIK_DECL xml_tree { public: xml_tree(std::string const& encoding="utf8"); diff --git a/src/rapidxml_loader.cpp b/src/rapidxml_loader.cpp index d380f0e88..97bcc503b 100644 --- a/src/rapidxml_loader.cpp +++ b/src/rapidxml_loader.cpp @@ -138,7 +138,11 @@ private: { if (cur_node->value_size() > 0) // Don't add empty text nodes { - node.add_child(cur_node->value(), 0, true); + // parsed text values should have leading and trailing + // whitespace trimmed. + std::string trimmed = cur_node->value(); + mapnik::util::trim(trimmed); + node.add_child(trimmed.c_str(), 0, true); } } break; diff --git a/test/unit/serialization/xml_parser_trim.cpp b/test/unit/serialization/xml_parser_trim.cpp new file mode 100644 index 000000000..250a23757 --- /dev/null +++ b/test/unit/serialization/xml_parser_trim.cpp @@ -0,0 +1,44 @@ +#include "catch.hpp" + +#include +#include +#include +#include + +TEST_CASE("xml parser") { + + SECTION("trims whitespace") { + + // simple and non-valid mapnik XML reduced from the empty_parameter2.xml + // test case. this is to check that the xml parsing routine is trimming + // whitespace from text nodes as part of the parsing operation. + const std::string xml("" + " " + " " + " " + " " + " " + ""); + + mapnik::xml_tree tree("utf8"); + tree.set_filename("xml_datasource_parameter_trim.cpp"); + REQUIRE_NOTHROW(read_xml_string(xml, tree.root(), "")); + + REQUIRE(tree.root().has_child("Map")); + mapnik::xml_node const &map = tree.root().get_child("Map"); + + REQUIRE(map.has_child("Layer")); + mapnik::xml_node const &layer = map.get_child("Layer"); + + REQUIRE(layer.has_child("Datasource")); + mapnik::xml_node const &datasource = layer.get_child("Datasource"); + + REQUIRE(datasource.has_child("Parameter")); + mapnik::xml_node const ¶meter = datasource.get_child("Parameter"); + + // parser should call mapnik::util::trim on the text content and + // this should result in an empty text string in the parameter. + REQUIRE(parameter.get_text() == ""); + } +} +