summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Paassen <bpaassen@techfak.uni-bielefeld.de>2015-02-22 11:48:19 +0100
committerBenjamin Paassen <bpaassen@techfak.uni-bielefeld.de>2015-02-22 11:48:19 +0100
commit255362d5f815ca0e04e18518bb3629d241af5117 (patch)
tree5e76d006f863c420eb5cd46a96ce2676717ee254
parente94dd497e760dcc72d048989f7d5d1c7e5aab862 (diff)
corrected XML serialization for primitive text content regarding whitespace and newline handling and extended XMLTest to check that.
-rw-r--r--src/core/XML.cpp114
-rw-r--r--test/core/XMLTest.cpp22
2 files changed, 94 insertions, 42 deletions
diff --git a/src/core/XML.cpp b/src/core/XML.cpp
index e25d18a..404af92 100644
--- a/src/core/XML.cpp
+++ b/src/core/XML.cpp
@@ -66,13 +66,82 @@ static std::string escapePredefinedEntities(const std::string &input)
void Element::doSerialize(std::ostream &out, unsigned int tabdepth, bool pretty)
{
+ bool hasText = false;
if (pretty) {
+ // print tabs at the beginning, if we are in pretty mode.
for (unsigned int t = 0; t < tabdepth; t++) {
out << '\t';
}
+ /*
+ * if we are in pretty mode we also need to check if we have a text
+ * node as child.
+ * If so this changes our further output processing because of the way
+ * XML treats primitive data: The structure
+ *
+ * \code{.xml}
+ * <Element name="A">
+ * <Text>content</Text>
+ * <Text>content2</Text>
+ * </Element>
+ * \endcode
+ *
+ * has to be serialized as
+ *
+ * \code{.xml}
+ * <A>contentcontent2</A>
+ * \endcode
+ *
+ * because otherwise we introduce whitespaces and newlines where no
+ * such things had been before.
+ *
+ * On the other hand the structure
+ *
+ * \code{.xml}
+ * <Element name="A">
+ * <Element name="B">
+ * <Text>content</Text>
+ * </Element>
+ * </Element>
+ * \endcode
+ *
+ * Can be serialized as
+ *
+ * \code{.xml}
+ * <A>
+ * <B>content</B>
+ * </A>
+ * \endcode
+ *
+ * As last example consider the case
+ *
+ * \code{.xml}
+ * <Element name="A">
+ * <Element name="B">
+ * <Text>content</Text>
+ * </Element>
+ * <Text>content2</Text>
+ * </Element>
+ * \endcode
+ *
+ * Here the A-Element again has primitive text content, such that we
+ * are not allowed to prettify. It has to be serialized like this:
+ *
+ * \code{.xml}
+ * <A><B>content</B>content2</A>
+ * \endcode
+ *
+ *
+ */
+ for (auto n : children) {
+ if (n->isa(&RttiTypes::XMLText)) {
+ hasText = true;
+ break;
+ }
+ }
}
+
out << '<';
- if(!nspace.empty()){
+ if (!nspace.empty()) {
out << nspace << ":";
}
out << name;
@@ -88,19 +157,19 @@ void Element::doSerialize(std::ostream &out, unsigned int tabdepth, bool pretty)
}
} else {
out << ">";
- if (pretty) {
+ if (pretty && !hasText) {
out << std::endl;
}
- for (auto &n : children) {
- n->doSerialize(out, tabdepth + 1, pretty);
+ for (auto n : children) {
+ n->doSerialize(out, tabdepth + 1, pretty && !hasText);
}
- if (pretty) {
+ if (pretty && !hasText) {
for (unsigned int t = 0; t < tabdepth; t++) {
out << '\t';
}
}
out << "</";
- if(!nspace.empty()){
+ if (!nspace.empty()) {
out << nspace << ":";
}
out << name << ">";
@@ -112,29 +181,20 @@ void Element::doSerialize(std::ostream &out, unsigned int tabdepth, bool pretty)
void Text::doSerialize(std::ostream &out, unsigned int tabdepth, bool pretty)
{
- if (pretty) {
- for (unsigned int t = 0; t < tabdepth; t++) {
- out << '\t';
- }
- }
out << escapePredefinedEntities(text);
- if (pretty) {
- out << std::endl;
- }
}
}
-namespace RttiTypes
-{
- const Rtti XMLNode = RttiBuilder<xml::Node>("XMLNode");
- const Rtti XMLElement =
- RttiBuilder<xml::Element>("XMLElement")
- .parent(&XMLNode)
- .composedOf(&XMLNode)
- .property("name", {&RttiTypes::String,
- {[](const xml::Element *obj) {
- return Variant::fromString(obj->getName());
- }}});
- const Rtti XMLText = RttiBuilder<xml::Text>("XMLText").parent(&XMLNode);
-}
+namespace RttiTypes {
+const Rtti XMLNode = RttiBuilder<xml::Node>("XMLNode");
+const Rtti XMLElement =
+ RttiBuilder<xml::Element>("XMLElement")
+ .parent(&XMLNode)
+ .composedOf(&XMLNode)
+ .property("name", {&RttiTypes::String,
+ {[](const xml::Element *obj) {
+ return Variant::fromString(obj->getName());
+ }}});
+const Rtti XMLText = RttiBuilder<xml::Text>("XMLText").parent(&XMLNode);
}
+} \ No newline at end of file
diff --git a/test/core/XMLTest.cpp b/test/core/XMLTest.cpp
index b11a24c..c264570 100644
--- a/test/core/XMLTest.cpp
+++ b/test/core/XMLTest.cpp
@@ -42,29 +42,21 @@ TEST(XMLNode, testSerialize)
body->addChild(div);
Rooted<Element> p{new Element{mgr, div, "p"}};
div->addChild(p);
- p->addChild(new Text(mgr, p, "my text"));
- Rooted<Element> p2{new Element{mgr, div, "p"}};
- div->addChild(p2);
- p2->addChild(new Text(mgr, p2, "my text"));
+ p->addChild(new Text(mgr, p, "A"));
+ div->addChild(new Text(mgr, div, "B"));
+ Rooted<Element> myTag{new Element{mgr, div, "myTag", {}, "myNameSpace"}};
+ div->addChild(myTag);
+ myTag->addChild(new Text(mgr, myTag, "C"));
// Now this is what we expect to see:
std::string expected{
"<?xml version=\"1.0\"?>\n"
"<html>\n"
"\t<head>\n"
- "\t\t<title>\n"
- "\t\t\tmy title\n"
- "\t\t</title>\n"
+ "\t\t<title>my title</title>\n"
"\t</head>\n"
"\t<body>\n"
- "\t\t<div class=\"content\" id=\"1\">\n"
- "\t\t\t<p>\n"
- "\t\t\t\tmy text\n"
- "\t\t\t</p>\n"
- "\t\t\t<p>\n"
- "\t\t\t\tmy text\n"
- "\t\t\t</p>\n"
- "\t\t</div>\n"
+ "\t\t<div class=\"content\" id=\"1\"><p>A</p>B<myNameSpace:myTag>C</myNameSpace:myTag></div>\n"
"\t</body>\n"
"</html>\n"};