/*
Ousía
Copyright (C) 2014 Benjamin Paaßen, Andreas Stöckel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include "DemoOutput.hpp"
namespace ousia {
namespace html {
void DemoHTMLTransformer::writeHTML(Handle doc,
std::ostream &out)
{
Manager &mgr = doc->getManager();
// Create an XML object tree for the document first.
Rooted html{new xml::Element{
mgr, "html", {{"xlmns", "http://www.w3.org/1999/xhtml"}}}};
// add the head Element
Rooted head{new xml::Element{mgr, "head"}};
html->children.push_back(head);
// add the meta element.
Rooted meta{
new xml::Element{mgr,
"meta",
{{"http-equiv", "Content-Type"},
{"content", "text/html; charset=utf-8"}}}};
head->children.push_back(meta);
// add the title Element with Text
Rooted 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 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 root = doc->getRoot();
if (root->getDescriptor()->getName() != "book") {
throw OusiaException("The given documents root is no book node!");
}
// transform the book node.
Rooted 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,
"");
}
/**
* This is just for easier internal handling.
*/
enum class SectionType { BOOK, SECTION, SUBSECTION, NONE };
SectionType getSectionType(const std::string &name)
{
if (name == "book") {
return SectionType::BOOK;
} else if (name == "section") {
return SectionType::SECTION;
} else if (name == "subsection") {
return SectionType::SUBSECTION;
} else {
return SectionType::NONE;
}
}
Rooted DemoHTMLTransformer::transformSection(
Handle section)
{
Manager &mgr = section->getManager();
// check the section type.
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 {nullptr};
}
// create a div tag containing the sections content.
Rooted sec{
new xml::Element{mgr, "div", {{"class", secclass}}}};
// check if we have a heading.
if (section->hasField("heading") &&
section->getField("heading").size() > 0) {
Rooted heading =
section->getField("heading")[0];
std::string headingclass;
switch (type) {
case SectionType::BOOK:
headingclass = "h1";
break;
case SectionType::SECTION:
headingclass = "h2";
break;
case SectionType::SUBSECTION:
headingclass = "h3";
break;
case SectionType::NONE:
// this can not happen;
break;
}
Rooted h{new xml::Element{mgr, headingclass}};
sec->children.push_back(h);
// extract the heading text, enveloped in a paragraph Element.
Rooted 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);
}
}
// Then we get all the children.
NodeVector mainField = section->getField();
for (auto &n : mainField) {
/*
* Strictly speaking this is the wrong mechanism, because we would have
* to make an "isa" call here because we can not rely on our knowledge
* that paragraphs can only be paragraphs or lists. There would have
* to be a listener structure of transformations that check if they can
* transform this specific node.
*/
const std::string childDescriptorName = n->getDescriptor()->getName();
Rooted child;
if (childDescriptorName == "paragraph") {
child = transformParagraph(n);
} else if (childDescriptorName == "ul" || childDescriptorName == "ol") {
child = transformList(n);
} else {
child = transformSection(n);
}
if (!child.isNull()) {
sec->children.push_back(child);
}
}
return sec;
}
Rooted DemoHTMLTransformer::transformParagraph(
Handle par)
{
Manager &mgr = par->getManager();
// create the p Element
Rooted p{new xml::Element{mgr, "p"}};
// check if we have a heading.
if (par->hasField("heading") && par->getField("heading").size() > 0) {
Rooted heading = par->getField("heading")[0];
// put the heading in a strong xml::Element.
Rooted strong{new xml::Element{mgr, "strong"}};
p->children.push_back(strong);
// extract the heading text, enveloped in a paragraph Element.
Rooted 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);
}
}
// transform paragraph children to XML as well
for (auto &n : par->getField()) {
std::string childDescriptorName = n->getDescriptor()->getName();
if (childDescriptorName == "text") {
Handle primitive =
n->getField()[0].cast();
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;
}
Rooted DemoHTMLTransformer::transformList(
Handle list)
{
Manager &mgr = list->getManager();
// create the list Element, which is either ul or ol (depends on descriptor)
std::string listclass = list->getDescriptor()->getName();
Rooted l{new xml::Element{mgr, listclass}};
// iterate through list items.
for (auto &item : list->getField()) {
std::string itDescrName = item->getDescriptor()->getName();
if (itDescrName == "item") {
// create the list item.
Rooted li{new xml::Element{mgr, "li"}};
l->children.push_back(li);
// extract the item text, enveloped in a paragraph Element.
Rooted li_content = transformParagraph(item);
// We omit the paragraph Element and add the children directly to
// the list item
for (auto &n : li_content->children) {
li->children.push_back(n);
}
}
}
return l;
}
}
}