summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/XML.cpp11
-rw-r--r--src/core/XML.hpp17
-rw-r--r--src/plugins/html/DemoOutput.cpp170
-rw-r--r--src/plugins/html/DemoOutput.hpp13
-rw-r--r--test/core/XMLTest.cpp1
5 files changed, 115 insertions, 97 deletions
diff --git a/src/core/XML.cpp b/src/core/XML.cpp
index ad69ba1..038cb86 100644
--- a/src/core/XML.cpp
+++ b/src/core/XML.cpp
@@ -4,7 +4,12 @@
namespace ousia {
namespace xml {
-void Element::serialize(std::ostream& out, unsigned int tabdepth)
+void Node::serialize(std::ostream& out){
+ out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ doSerialize(out, 0);
+}
+
+void Element::doSerialize(std::ostream& out, unsigned int tabdepth)
{
for (unsigned int t = 0; t < tabdepth; t++) {
out << '\t';
@@ -15,7 +20,7 @@ void Element::serialize(std::ostream& out, unsigned int tabdepth)
}
out << ">\n";
for (auto &n : children) {
- n->serialize(out, tabdepth + 1);
+ n->doSerialize(out, tabdepth + 1);
}
for (unsigned int t = 0; t < tabdepth; t++) {
out << '\t';
@@ -23,7 +28,7 @@ void Element::serialize(std::ostream& out, unsigned int tabdepth)
out << "</" << name << ">\n";
}
-void Text::serialize(std::ostream& out, unsigned int tabdepth)
+void Text::doSerialize(std::ostream& out, unsigned int tabdepth)
{
for (unsigned int t = 0; t < tabdepth; t++) {
out << '\t';
diff --git a/src/core/XML.hpp b/src/core/XML.hpp
index 824d6ce..9ca124a 100644
--- a/src/core/XML.hpp
+++ b/src/core/XML.hpp
@@ -57,18 +57,25 @@ namespace xml {
* implement.
*/
class Node : public Managed {
+
public:
Node(Manager &mgr) : Managed(mgr){};
/**
- * When called this Node should serialize its data and write it to the
- * given output stream. In case of Elements this includes child elements.
+ * This method writes an XML prolog and the XML representing the current
+ * node, including all children, to the given output stream.
+ * @param out is the output stream the serialized data shall be written to.
+ */
+ void serialize(std::ostream &out);
+ /**
+ * This method just writes the XML representation of this node to the
+ * output stream, without the XML prolog.
*
* @param out the output stream the serialized data shall be written
* to.
* @param tabdepth the current tabdepth for prettier output.
*/
- virtual void serialize(std::ostream &out, unsigned int tabdepth) = 0;
+ virtual void doSerialize(std::ostream &out, unsigned int tabdepth) = 0;
};
/**
@@ -103,7 +110,7 @@ public:
* * The end tag of this element.
*
*/
- void serialize(std::ostream &out, unsigned int tabdepth = 0) override;
+ void doSerialize(std::ostream &out, unsigned int tabdepth) override;
};
class Text : public Node {
@@ -116,7 +123,7 @@ public:
* This just writes the text to the output.
*
*/
- void serialize(std::ostream &out, unsigned int tabdepth = 0) override;
+ void doSerialize(std::ostream &out, unsigned int tabdepth) override;
};
}
}
diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp
index 463a5d2..035ba25 100644
--- a/src/plugins/html/DemoOutput.cpp
+++ b/src/plugins/html/DemoOutput.cpp
@@ -18,6 +18,7 @@
#include <core/common/Exceptions.hpp>
#include <core/common/Rtti.hpp>
+#include <core/common/Variant.hpp>
#include "DemoOutput.hpp"
@@ -27,24 +28,35 @@ namespace html {
void DemoHTMLTransformer::writeHTML(Handle<model::Document> doc,
std::ostream &out)
{
- // write preamble
- out << "<?xml version=\" 1.0 \"?>\n";
- out << "<html>\n";
- out << "\t<head>\n";
- out << "\t\t<title>Test HTML Output for " << doc->getName() << "</title>\n";
- out << "\t</head>\n";
- out << "\t<body>\n";
-
- // look for the book root node.
+ Manager &mgr = doc->getManager();
+ // Create an XML object tree for the document first.
+ Rooted<xml::Element> html{new xml::Element{mgr, "html"}};
+ // add the head Element
+ Rooted<xml::Element> head{new xml::Element{mgr, "head"}};
+ html->children.push_back(head);
+ // add the title Element with Text
+ Rooted<xml::Element> title{new xml::Element{mgr, "title"}};
+ head->children.push_back(title);
+ title->children.push_back(
+ new xml::Text(mgr, "Test HTML Output for " + doc->getName()));
+ // add the body Element
+ Rooted<xml::Element> body{new xml::Element{mgr, "body"}};
+ html->children.push_back(body);
+
+ // So far was the "preamble". No we have to get to the document content.
+
+ // extract the book root node.
Rooted<model::StructuredEntity> root = doc->getRoot();
if (root->getDescriptor()->getName() != "book") {
throw OusiaException("The given documents root is no book node!");
}
- // write it to HTML.
- writeSection(root, out);
- // write end
- out << "\t</body>\n";
- out << "</html>\n";
+ // transform the book node.
+ Rooted<xml::Element> book = transformSection(root);
+ // add it as child to the body node.
+ body->children.push_back(book);
+
+ // After the content has been transformed, we serialize it.
+ html->serialize(out);
}
/**
@@ -67,61 +79,54 @@ SectionType getSectionType(const std::string &name)
}
}
-void DemoHTMLTransformer::writeSection(Handle<model::StructuredEntity> sec,
- std::ostream &out)
+Rooted<xml::Element> DemoHTMLTransformer::transformSection(Handle<model::StructuredEntity> section)
{
+ Manager &mgr = section->getManager();
// check the section type.
- SectionType type = getSectionType(sec->getDescriptor()->getName());
+ const std::string secclass = section->getDescriptor()->getName();
+ SectionType type = getSectionType(secclass);
if (type == SectionType::NONE) {
// if the input node is no section, we ignore it.
- return;
+ return {nullptr};
}
+ // create a div tag containing the sections content.
+ Rooted<xml::Element> sec{
+ new xml::Element{mgr, "div", {{"class", secclass}}}};
// check if we have a heading.
- if (sec->hasField("heading")) {
- Rooted<model::StructuredEntity> heading = sec->getField("heading")[0];
- out << "\t\t";
+ if (section->hasField("heading")) {
+ Rooted<model::StructuredEntity> heading =
+ section->getField("heading")[0];
+ std::string headingclass;
switch (type) {
case SectionType::BOOK:
- out << "<h1>";
+ headingclass = "h1";
break;
case SectionType::CHAPTER:
- out << "<h2>";
+ headingclass = "h2";
break;
case SectionType::SECTION:
- out << "<h3>";
+ headingclass = "h3";
break;
case SectionType::SUBSECTION:
- out << "<h4>";
+ headingclass = "h4";
break;
case SectionType::NONE:
// this can not happen;
break;
}
- // the second field marks the heading. So let's write it.
- writeParagraph(heading, out, false);
- // close the heading tag.
- switch (type) {
- case SectionType::BOOK:
- out << "</h1>";
- break;
- case SectionType::CHAPTER:
- out << "</h2>";
- break;
- case SectionType::SECTION:
- out << "</h3>";
- break;
- case SectionType::SUBSECTION:
- out << "</h4>";
- break;
- case SectionType::NONE:
- // this can not happen;
- break;
+ Rooted<xml::Element> h{new xml::Element{mgr, headingclass}};
+ sec->children.push_back(h);
+ // extract the heading text, enveloped in a paragraph Element.
+ Rooted<xml::Element> h_content = transformParagraph(heading);
+ // We omit the paragraph Element and add the children directly to the
+ // heading Element
+ for (auto &n : h_content->children) {
+ h->children.push_back(n);
}
- out << "\n";
}
- // then write the section content recursively.
- NodeVector<model::StructuredEntity> mainField = sec->getField();
+ // Then we get all the children.
+ NodeVector<model::StructuredEntity> mainField = section->getField();
for (auto &n : mainField) {
/*
* Strictly speaking this is the wrong mechanism, because we would have
@@ -130,56 +135,59 @@ void DemoHTMLTransformer::writeSection(Handle<model::StructuredEntity> sec,
* to be a listener structure of transformations that check if they can
* transform this specific node.
*/
- std::string childDescriptorName = n->getDescriptor()->getName();
+ const std::string childDescriptorName = n->getDescriptor()->getName();
+ Rooted<xml::Element> child;
if (childDescriptorName == "paragraph") {
- writeParagraph(n, out);
+ child = transformParagraph(n);
// TODO: Implement
// } else if(childDescriptorName == "ul"){
// writeList(n, out);
} else {
- writeSection(n, out);
+ child = transformSection(n);
+ }
+ if (!child.isNull()) {
+ sec->children.push_back(child);
}
}
+ return sec;
}
-void DemoHTMLTransformer::writeParagraph(Handle<model::StructuredEntity> par,
- std::ostream &out, bool writePTags)
+Rooted<xml::Element> DemoHTMLTransformer::transformParagraph(Handle<model::StructuredEntity> par)
{
- // validate descriptor.
- if (par->getDescriptor()->getName() != "paragraph") {
- throw OusiaException("Expected paragraph!");
- }
+ Manager &mgr = par->getManager();
+ // create the p xml::Element
+ Rooted<xml::Element> p{new xml::Element{mgr, "p"}};
+
// check if we have a heading.
if (par->hasField("heading")) {
Rooted<model::StructuredEntity> heading = par->getField("heading")[0];
- // start the heading tag
- out << "\t\t<h5>";
- // the second field marks the heading. So let's write it.
- writeParagraph(heading, out, false);
- // close the heading tag.
- out << "</h5>\n";
- }
- // write start tag
- if (writePTags) {
- out << "\t\t<p>";
- }
- // write content
- // TODO: What about emphasis?
- for (auto &text : par->getField()) {
- if (text->getDescriptor()->getName() != "text") {
- throw OusiaException("Expected text!");
+ // put the heading in a strong xml::Element.
+ Rooted<xml::Element> strong{new xml::Element{mgr, "strong"}};
+ p->children.push_back(strong);
+ // extract the heading text, enveloped in a paragraph Element.
+ Rooted<xml::Element> h_content = transformParagraph(heading);
+ // We omit the paragraph Element and add the children directly to the
+ // heading Element
+ for (auto &n : h_content->children) {
+ strong->children.push_back(n);
}
- Handle<model::DocumentPrimitive> primitive =
- text->getField()[0].cast<model::DocumentPrimitive>();
- if (primitive.isNull()) {
- throw OusiaException("Text field is not primitive!");
- }
- out << primitive->getContent().asString();
}
- // write end tag
- if (writePTags) {
- out << "</p>\n";
+
+ // transform paragraph children to XML as well
+ for (auto &n : par->getField()) {
+ std::string childDescriptorName = n->getDescriptor()->getName();
+ if (childDescriptorName == "text") {
+ Handle<model::DocumentPrimitive> primitive =
+ n->getField()[0].cast<model::DocumentPrimitive>();
+ if (primitive.isNull()) {
+ throw OusiaException("Text field is not primitive!");
+ }
+ p->children.push_back(
+ new xml::Text(mgr, primitive->getContent().asString()));
+ }
+ // TODO: Handle non-text content
}
+ return p;
}
}
}
diff --git a/src/plugins/html/DemoOutput.hpp b/src/plugins/html/DemoOutput.hpp
index ca9bcd2..70a5daa 100644
--- a/src/plugins/html/DemoOutput.hpp
+++ b/src/plugins/html/DemoOutput.hpp
@@ -33,6 +33,7 @@
#include <ostream>
#include <core/model/Document.hpp>
+#include <core/XML.hpp>
namespace ousia {
namespace html {
@@ -40,15 +41,11 @@ namespace html {
class DemoHTMLTransformer {
private:
/**
- * This method is to be called recursively to write a chapter, section or
- * subsection to HTML.
+ * These methods are called recursively to transform a document to an XML
+ * tree.
*/
- void writeSection(Handle<model::StructuredEntity> sec, std::ostream& out);
- /**
- * This method is to be called recursively to write a paragraph to HTML.
- */
- void writeParagraph(Handle<model::StructuredEntity> par, std::ostream& out,
- bool writePTags = true);
+ Rooted<xml::Element> transformSection(Handle<model::StructuredEntity> sec);
+ Rooted<xml::Element> transformParagraph(Handle<model::StructuredEntity> par);
/**
* This method is to be called recursively to write a list to HTML.
* TODO: Implement
diff --git a/test/core/XMLTest.cpp b/test/core/XMLTest.cpp
index aeedb86..124b58d 100644
--- a/test/core/XMLTest.cpp
+++ b/test/core/XMLTest.cpp
@@ -50,6 +50,7 @@ TEST(Node, testSerialize)
// Now this is what we expect to see:
std::string expected{
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<html>\n"
"\t<head>\n"
"\t\t<title>\n"