summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/XML.cpp7
-rw-r--r--src/core/XML.hpp23
-rw-r--r--src/core/managed/Manager.cpp8
-rw-r--r--src/core/model/Document.cpp157
-rw-r--r--src/core/model/Document.hpp109
-rw-r--r--src/plugins/html/DemoOutput.cpp36
-rw-r--r--test/core/XMLTest.cpp21
-rw-r--r--test/core/model/DocumentTest.cpp6
-rw-r--r--test/core/model/TestAdvanced.hpp97
-rw-r--r--test/core/model/TestDocument.hpp21
-rw-r--r--test/core/model/TestDocumentBuilder.hpp300
-rw-r--r--test/plugins/html/DemoOutputTest.cpp7
12 files changed, 428 insertions, 364 deletions
diff --git a/src/core/XML.cpp b/src/core/XML.cpp
index 7f03b35..affa75f 100644
--- a/src/core/XML.cpp
+++ b/src/core/XML.cpp
@@ -45,4 +45,11 @@ void Text::doSerialize(std::ostream &out, unsigned int tabdepth)
out << text << '\n';
}
}
+
+namespace RttiTypes {
+const Rtti<xml::Node> XMLNode = RttiBuilder("XMLNode");
+const Rtti<xml::Element> XMLElement =
+ RttiBuilder("XMLElement").parent(&XMLNode).composedOf(&XMLNode);
+const Rtti<xml::Text> XMLText = RttiBuilder("XMLText").parent(&XMLNode);
+}
}
diff --git a/src/core/XML.hpp b/src/core/XML.hpp
index b4b803d..25c8dae 100644
--- a/src/core/XML.hpp
+++ b/src/core/XML.hpp
@@ -45,6 +45,7 @@
#include <ostream>
#include <vector>
+#include <core/common/Rtti.hpp>
#include <core/managed/Managed.hpp>
#include <core/managed/ManagedContainer.hpp>
@@ -101,19 +102,22 @@ public:
* Additionally it might have other Nodes as children.
*/
class Element : public Node {
+private:
+ ManagedVector<Node> children;
+
public:
const std::string name;
std::map<std::string, std::string> attributes;
- ManagedVector<Node> children;
Element(Manager &mgr, Handle<Element> parent, std::string name)
- : Node(mgr, parent), name(std::move(name))
+ : Node(mgr, parent), children(this), name(std::move(name))
{
}
Element(Manager &mgr, Handle<Element> parent, std::string name,
std::map<std::string, std::string> attributes)
: Node(mgr, parent),
+ children(this),
name(std::move(name)),
attributes(std::move(attributes))
{
@@ -127,6 +131,15 @@ public:
*
*/
void doSerialize(std::ostream &out, unsigned int tabdepth) override;
+
+ const ManagedVector<Node> &getChildren() const { return children; }
+
+ void addChild(Handle<Node> child) { children.push_back(child); }
+
+ void addChildren(std::vector<Handle<Node>> c)
+ {
+ children.insert(children.end(), c.begin(), c.end());
+ }
};
class Text : public Node {
@@ -145,5 +158,11 @@ public:
void doSerialize(std::ostream &out, unsigned int tabdepth) override;
};
}
+
+namespace RttiTypes {
+extern const Rtti<xml::Node> XMLNode;
+extern const Rtti<xml::Element> XMLElement;
+extern const Rtti<xml::Text> XMLText;
+}
}
#endif
diff --git a/src/core/managed/Manager.cpp b/src/core/managed/Manager.cpp
index 5428ea1..3950ce2 100644
--- a/src/core/managed/Manager.cpp
+++ b/src/core/managed/Manager.cpp
@@ -26,8 +26,9 @@
#if defined(MANAGER_DEBUG_PRINT) || defined(MANAGER_GRAPHVIZ_EXPORT)
#include <iostream>
#include <fstream>
-#include "core/common/Rtti.hpp"
-#include "core/model/Node.hpp"
+#include <core/common/Rtti.hpp>
+#include <core/model/Node.hpp>
+#include <core/XML.hpp>
#endif
namespace ousia {
@@ -598,6 +599,9 @@ void Manager::exportGraphviz(const char *filename)
if (type.isa(RttiTypes::Node)) {
name = dynamic_cast<const Node *>(objectPtr)->getName();
}
+ if (type.isa(RttiTypes::XMLElement)) {
+ name = dynamic_cast<const xml::Element *>(objectPtr)->name;
+ }
// Print the node
uintptr_t p = reinterpret_cast<uintptr_t>(objectPtr);
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp
index 5386525..912a04e 100644
--- a/src/core/model/Document.cpp
+++ b/src/core/model/Document.cpp
@@ -89,163 +89,6 @@ NodeVector<StructuredEntity> &DocumentEntity::getField(
"node.");
}
-/* Class StructuredEntity */
-
-static Rooted<Descriptor> resolveDescriptor(std::vector<Handle<Domain>> domains,
- const std::string &className,
- const RttiBase &type)
-{
- // iterate over all domains.
- for (auto &d : domains) {
- // use the actual resolve method.
- std::vector<ResolutionResult> resolved = d->resolve(className, type);
- // if we don't find anything, continue.
- if (resolved.size() == 0) {
- continue;
- }
- // Otherwise take the first valid result.
- for (auto &r : resolved) {
- return r.node.cast<Descriptor>();
- }
- }
- return {nullptr};
-}
-
-Rooted<StructuredEntity> StructuredEntity::buildRootEntity(
- Handle<Document> document, std::vector<Handle<Domain>> domains,
- const std::string &className, Variant attributes, std::string name)
-{
- // If the parent is not set, we can not build the entity.
- if (document == nullptr) {
- return {nullptr};
- }
- // If we can not find the correct descriptor, we can not build the entity
- // either.
- Rooted<Descriptor> descriptor =
- resolveDescriptor(domains, className, RttiTypes::StructuredClass);
- if (descriptor == nullptr) {
- return {nullptr};
- }
- // Then construct the StructuredEntity itself.
- Rooted<StructuredEntity> root{new StructuredEntity(
- document->getManager(), document, descriptor.cast<StructuredClass>(),
- attributes, std::move(name))};
- // append it to the document.
- document->setRoot(root);
- // and return it.
- return root;
-}
-
-Rooted<StructuredEntity> StructuredEntity::buildEntity(
- Handle<DocumentEntity> parent, std::vector<Handle<Domain>> domains,
- const std::string &className, const std::string &fieldName,
- Variant attributes, std::string name)
-{
- // If the parent is not set, we can not build the entity.
- if (parent == nullptr) {
- return {nullptr};
- }
- // If we can not find the correct descriptor, we can not build the entity
- // either.
- Rooted<Descriptor> descriptor =
- resolveDescriptor(domains, className, RttiTypes::StructuredClass);
- if (descriptor == nullptr) {
- return {nullptr};
- }
- // Then construct the StructuredEntity itself.
- Rooted<StructuredEntity> entity{new StructuredEntity(
- parent->getManager(), parent, descriptor.cast<StructuredClass>(),
- attributes, std::move(name))};
- // if the field does not exist, return null handle as well.
- if (!parent->hasField(fieldName)) {
- return {nullptr};
- }
- // append the new entity to the right field.
- if (!parent->hasField(fieldName)) {
- return {nullptr};
- }
- NodeVector<StructuredEntity> &field = parent->getField(fieldName);
- field.push_back(entity);
-
- // and return it.
- return entity;
-}
-
-/* Class DocumentPrimitive */
-
-Rooted<DocumentPrimitive> DocumentPrimitive::buildEntity(
- Handle<DocumentEntity> parent, Variant content,
- const std::string &fieldName)
-{
- // If the parent is not set, we can not build the entity.
- if (parent == nullptr) {
- return {nullptr};
- }
- // Then construct the StructuredEntity itself.
- Rooted<DocumentPrimitive> entity{
- new DocumentPrimitive(parent->getManager(), parent, content)};
- // if the field does not exist, return null handle as well.
- if (!parent->hasField(fieldName)) {
- return {nullptr};
- }
- // append the new entity to the right field.
- if (!parent->hasField(fieldName)) {
- return {nullptr};
- }
- NodeVector<StructuredEntity> &field = parent->getField(fieldName);
- field.push_back(entity);
- // and return it.
- return entity;
-}
-
-/* Class AnnotationEntity */
-
-Rooted<AnnotationEntity::Anchor> AnnotationEntity::buildAnchor(
- Handle<DocumentEntity> parent, std::string id, const std::string &fieldName)
-{
- // If the parent is not set, we can not build the anchor.
- if (parent == nullptr) {
- return {nullptr};
- }
- // Then construct the Anchor itself
- Rooted<Anchor> anchor{
- new AnnotationEntity::Anchor(parent->getManager(), parent, id)};
- // append the new entity to the right field.
- if (!parent->hasField(fieldName)) {
- return {nullptr};
- }
- NodeVector<StructuredEntity> &field = parent->getField(fieldName);
- field.push_back(anchor);
- // and return it.
- return anchor;
-}
-
-Rooted<AnnotationEntity> AnnotationEntity::buildEntity(
- Handle<Document> parent, std::vector<Handle<Domain>> domains,
- const std::string &className, Handle<AnnotationEntity::Anchor> start,
- Handle<AnnotationEntity::Anchor> end, Variant attributes, std::string name)
-{
- // If the parent is not set, we can not build the AnnotationEntity.
- if (parent == nullptr) {
- return {nullptr};
- }
- // If we can not find the correct descriptor, we can not build the entity
- // either.
- Rooted<Descriptor> descriptor =
- resolveDescriptor(domains, className, RttiTypes::AnnotationClass);
- if (descriptor == nullptr) {
- return {nullptr};
- }
- // Then construct the AnnotationEntity itself
- Rooted<AnnotationEntity> anno{new AnnotationEntity(
- parent->getManager(), parent, descriptor.cast<AnnotationClass>(),
- attributes, start, end, name)};
- // append the new entity to the document
- parent->getAnnotations().push_back(anno);
- // and return it.
- return anno;
-}
-
/* Class Document */
void Document::continueResolve(ResolutionState &state)
diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp
index 466185b..c367e50 100644
--- a/src/core/model/Document.hpp
+++ b/src/core/model/Document.hpp
@@ -215,57 +215,6 @@ public:
std::move(name))
{
}
-
- /**
- * This builds the root StructuredEntity for the given document. It
- * automatically appends the newly build entity to the given document.
- *
- * @param document is the document this entity shall be build for. The
- * resulting entity will automatically be appended to that
- * document. Also the manager of that document will be
- * used to register the new node.
- * @param domains are the domains that are used to find the
- * StructuredClass for the new node. The domains will be
- * searched in the given order.
- * @param className is the name of the StructuredClass.
- * @param attributes are the attributes of the new node in terms of a Struct
- * variant (empty per default).
- * @param name is the name of this StructuredEntity (empty per
- * default).
- * @return the newly created StructuredEntity or a nullptr if some
- * input handle was empty or the given domains did not
- * contain a StructuredClass with the given name.
- */
- static Rooted<StructuredEntity> buildRootEntity(
- Handle<Document> document, std::vector<Handle<Domain>> domains,
- const std::string &className, Variant attributes = Variant(),
- std::string name = "");
-
- /**
- * This builds a StructuredEntity as child of the given DocumentEntity. It
- * automatically appends the newly build entity to its parent.
- *
- * @param parent is the parent DocumentEntity. The newly constructed
- * StructuredEntity will automatically be appended to it.
- * @param domains are the domains that are used to find the
- * StructuredClass for the new node. The domains will be
- * searched in the given order.
- * @param className is the name of the StructuredClass.
- * @param fieldName is the name of the field where the newly constructed
- * StructuredEntity shall be appended.
- * @param attributes are the attributes of the new node in terms of a Struct
- * variant (empty per default).
- * @param name is the name of this StructuredEntity (empty per
- * default).
- *
- * @return the newly created StructuredEntity or a nullptr if some
- * input handle was empty or the given domains did not
- * contain a StructuredClass with the given name.
- */
- static Rooted<StructuredEntity> buildEntity(
- Handle<DocumentEntity> parent, std::vector<Handle<Domain>> domains,
- const std::string &className, const std::string &fieldName = "",
- Variant attributes = Variant(), std::string name = "");
};
/**
@@ -284,25 +233,6 @@ public:
Variant getContent() const { return getAttributes(); }
// TODO: Override such methods like "getField" to disable them?
-
- /**
- * This builds a DocumentPrimitive as child of the given DocumentEntity. It
- * automatically appends the newly build entity to its parent.
- *
- * @param parent is the parent DocumentEntity. The newly constructed
- * DocumentPrimitive will automatically be appended to it.
- * @param content is the primitive content of the new node in terms of a
- * Struct variant.
- * @param fieldName is the name of the field where the newly constructed
- * StructuredEntity shall be appended.
- *
- * @return the newly created StructuredEntity or a nullptr if some
- * input handle was empty or the given domains did not
- * contain a StructuredClass with the given name.
- */
- static Rooted<DocumentPrimitive> buildEntity(
- Handle<DocumentEntity> parent, Variant content,
- const std::string &fieldName = "");
};
/**
@@ -365,45 +295,6 @@ public:
Rooted<Anchor> getStart() { return start; }
Rooted<Anchor> getEnd() { return end; }
-
- /**
- * This builds an Anchor as child of the given DocumentEntity. It
- * automatically appends the newly build Anchor to its parent.
- *
- * @param parent is the parent DocumentEntity. The newly constructed
- * Anchor will automatically be appended to it.
- * @param id is the id of this Anchor.
- * @param fieldName is the name of the field where the newly constructed
- * Anchor shall be appended.
- *
- * @return the newly created Anchor or a nullptr if some
- * input handle was empty.
- */
- static Rooted<Anchor> buildAnchor(Handle<DocumentEntity> parent,
- std::string id,
- const std::string &fieldName = "");
- /**
- * This builds an AnnotationEntity as child of the given DocumentEntity. It
- * automatically appends the newly build entity to its parent.
- *
- * @param parent is the document the newly constructed AnnotationEntity
- * will be appended to.
- * @param domains are the domains that are used to find the
- * AnnotationClass for the new node. The domains will be
- * searched in the given order.
- * @param className is the name of the AnnotationClass.
- * @param attributes are the attributes of the new node in terms of a Struct
- * variant (empty per default).
- * @param name is the name of this AnnotationEntity (empty per
- * default).
- * @return the newly created AnnotationEntity or a nullptr if some
- * input handle was empty or the given domains did not
- * contain a AnnotationClass with the given name.
- */
- static Rooted<AnnotationEntity> buildEntity(Handle<Document> parent, std::vector<Handle<Domain>> domains,
- const std::string &className,
- Handle<Anchor> start, Handle<Anchor> end,
- Variant attributes = Variant(), std::string name = "");
};
/**
diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp
index 3bd5918..5413b1f 100644
--- a/src/plugins/html/DemoOutput.cpp
+++ b/src/plugins/html/DemoOutput.cpp
@@ -37,7 +37,7 @@ void DemoHTMLTransformer::writeHTML(Handle<model::Document> doc,
mgr, {nullptr}, "html", {{"xlmns", "http://www.w3.org/1999/xhtml"}}}};
// add the head Element
Rooted<xml::Element> head{new xml::Element{mgr, html, "head"}};
- html->children.push_back(head);
+ html->addChild(head);
// add the meta element.
Rooted<xml::Element> meta{
new xml::Element{mgr,
@@ -45,15 +45,15 @@ void DemoHTMLTransformer::writeHTML(Handle<model::Document> doc,
"meta",
{{"http-equiv", "Content-Type"},
{"content", "text/html; charset=utf-8"}}}};
- head->children.push_back(meta);
+ head->addChild(meta);
// add the title Element with Text
Rooted<xml::Element> title{new xml::Element{mgr, head, "title"}};
- head->children.push_back(title);
- title->children.push_back(
+ head->addChild(title);
+ title->addChild(
new xml::Text(mgr, title, "Test HTML Output for " + doc->getName()));
// add the body Element
Rooted<xml::Element> body{new xml::Element{mgr, html, "body"}};
- html->children.push_back(body);
+ html->addChild(body);
// So far was the "preamble". No we have to get to the document content.
@@ -75,7 +75,7 @@ void DemoHTMLTransformer::writeHTML(Handle<model::Document> doc,
// transform the book node.
Rooted<xml::Element> book = transformSection(body, root, startMap, endMap);
// add it as child to the body node.
- body->children.push_back(book);
+ body->addChild(book);
// After the content has been transformed, we serialize it.
html->serialize(
@@ -138,14 +138,14 @@ Rooted<xml::Element> DemoHTMLTransformer::transformSection(
break;
}
Rooted<xml::Element> h{new xml::Element{mgr, sec, headingclass}};
- sec->children.push_back(h);
+ sec->addChild(h);
// extract the heading text, enveloped in a paragraph Element.
Rooted<xml::Element> h_content =
transformParagraph(h, heading, startMap, endMap);
// 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);
+ for (auto &n : h_content->getChildren()) {
+ h->addChild(n);
}
}
@@ -169,7 +169,7 @@ Rooted<xml::Element> DemoHTMLTransformer::transformSection(
child = transformSection(sec, n, startMap, endMap);
}
if (!child.isNull()) {
- sec->children.push_back(child);
+ sec->addChild(child);
}
}
return sec;
@@ -189,14 +189,14 @@ Rooted<xml::Element> DemoHTMLTransformer::transformList(
if (itDescrName == "item") {
// create the list item.
Rooted<xml::Element> li{new xml::Element{mgr, l, "li"}};
- l->children.push_back(li);
+ l->addChild(li);
// extract the item text, enveloped in a paragraph Element.
Rooted<xml::Element> li_content =
transformParagraph(li, item, startMap, endMap);
// 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);
+ for (auto &n : li_content->getChildren()) {
+ li->addChild(n);
}
}
}
@@ -220,7 +220,7 @@ static Rooted<xml::Element> openAnnotation(
}
// create the new XML element representing the annotation
Rooted<xml::Element> tmp{new xml::Element{mgr, current, elemName}};
- current->children.push_back(tmp);
+ current->addChild(tmp);
// and return it.
return tmp;
}
@@ -265,14 +265,14 @@ Rooted<xml::Element> DemoHTMLTransformer::transformParagraph(
Rooted<model::StructuredEntity> heading = par->getField("heading")[0];
// put the heading in a strong xml::Element.
Rooted<xml::Element> strong{new xml::Element{mgr, p, "strong"}};
- p->children.push_back(strong);
+ p->addChild(strong);
// extract the heading text, enveloped in a paragraph Element.
Rooted<xml::Element> h_content =
transformParagraph(strong, heading, startMap, endMap);
// 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);
+ for (auto &n : h_content->getChildren()) {
+ strong->addChild(n);
}
}
@@ -346,7 +346,7 @@ Rooted<xml::Element> DemoHTMLTransformer::transformParagraph(
// here we need to do some escaping with the string content.
std::string escaped =
escapePredefinedEntities(primitive->getContent().asString());
- current->children.push_back(new xml::Text(mgr, current, escaped));
+ current->addChild(new xml::Text(mgr, current, escaped));
}
}
return p;
diff --git a/test/core/XMLTest.cpp b/test/core/XMLTest.cpp
index 2623342..f7a0b4a 100644
--- a/test/core/XMLTest.cpp
+++ b/test/core/XMLTest.cpp
@@ -27,26 +27,25 @@ namespace xml {
TEST(XMLNode, testSerialize)
{
- Manager mgr;
-
+ Manager mgr{1};
Rooted<Element> html{new Element{mgr, {nullptr}, "html"}};
Rooted<Element> head{new Element{mgr, html, "head"}};
- html->children.push_back(head);
+ html->addChild(head);
Rooted<Element> title{new Element{mgr, head, "title"}};
- head->children.push_back(title);
- title->children.push_back(new Text(mgr, title, "my title"));
+ head->addChild(title);
+ title->addChild(new Text(mgr, title, "my title"));
Rooted<Element> body{new Element{mgr, html, "body"}};
- html->children.push_back(body);
+ html->addChild(body);
// This div element contains our text.
Rooted<Element> div{
new Element{mgr, body, "div", {{"class", "content"}, {"id", "1"}}}};
- body->children.push_back(div);
+ body->addChild(div);
Rooted<Element> p{new Element{mgr, div, "p"}};
- div->children.push_back(p);
- p->children.push_back(new Text(mgr, p, "my text"));
+ div->addChild(p);
+ p->addChild(new Text(mgr, p, "my text"));
Rooted<Element> p2{new Element{mgr, div, "p"}};
- div->children.push_back(p2);
- p2->children.push_back(new Text(mgr, p2, "my text"));
+ div->addChild(p2);
+ p2->addChild(new Text(mgr, p2, "my text"));
// Now this is what we expect to see:
std::string expected{
diff --git a/test/core/model/DocumentTest.cpp b/test/core/model/DocumentTest.cpp
index c86b285..2d53dcd 100644
--- a/test/core/model/DocumentTest.cpp
+++ b/test/core/model/DocumentTest.cpp
@@ -18,6 +18,8 @@
#include <gtest/gtest.h>
+#include <iostream>
+
#include <core/model/Document.hpp>
#include <core/model/Domain.hpp>
@@ -30,13 +32,13 @@ namespace model {
TEST(Document, testDocumentConstruction)
{
// Construct Manager
- Logger logger;
+ TerminalLogger logger {std::cerr, true};
Manager mgr{1};
Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
// Get the domain.
Rooted<Domain> domain = constructBookDomain(mgr, sys, logger);
// Construct the document.
- Rooted<Document> doc = constructBookDocument(mgr, domain);
+ Rooted<Document> doc = constructBookDocument(mgr, logger, domain);
// Check the document content.
ASSERT_FALSE(doc.isNull());
diff --git a/test/core/model/TestAdvanced.hpp b/test/core/model/TestAdvanced.hpp
index 59d79ad..a1510e7 100644
--- a/test/core/model/TestAdvanced.hpp
+++ b/test/core/model/TestAdvanced.hpp
@@ -16,13 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _MODEL_TEST_DOCUMENT_HPP_
-#define _MODEL_TEST_DOCUMENT_HPP_
+#ifndef _MODEL_TEST_ADVANCED_HPP_
+#define _MODEL_TEST_ADVANCED_HPP_
#include <core/model/Document.hpp>
#include <core/model/Domain.hpp>
#include <core/model/Typesystem.hpp>
+#include "TestDocumentBuilder.hpp"
+
namespace ousia {
namespace model {
@@ -30,7 +32,8 @@ static Rooted<StructuredClass> resolveDescriptor(Handle<Domain> domain,
const std::string &className)
{
// use the actual resolve method.
- std::vector<ResolutionResult> resolved = domain->resolve(className, typeOf<StructuredClass>());
+ std::vector<ResolutionResult> resolved =
+ domain->resolve(className, typeOf<StructuredClass>());
// take the first valid result.
for (auto &r : resolved) {
return r.node.cast<StructuredClass>();
@@ -126,20 +129,19 @@ static Rooted<Domain> constructEmphasisDomain(Manager &mgr,
return domain;
}
-static bool addText(Handle<StructuredEntity> parent,
- std::vector<Handle<Domain>> &doms,
- const std::string &content)
+static bool addText(Logger &logger, Handle<Document> doc,
+ Handle<StructuredEntity> parent, const std::string &content)
{
- // Add its text.
+ // Add the text.
Rooted<StructuredEntity> text =
- StructuredEntity::buildEntity(parent, doms, "text");
+ buildStructuredEntity(doc, logger, parent, {"text"});
if (text.isNull()) {
return false;
}
- // And its primitive content
+ // And the primitive content
Variant content_var{content.c_str()};
Rooted<DocumentPrimitive> primitive =
- DocumentPrimitive::buildEntity(text, content_var, "content");
+ buildPrimitiveEntity(logger, text, content_var, "content");
if (primitive.isNull()) {
return false;
}
@@ -147,18 +149,17 @@ static bool addText(Handle<StructuredEntity> parent,
return true;
}
-static bool addHeading(Handle<StructuredEntity> parent,
- std::vector<Handle<Domain>> &doms,
- const std::string &text)
+static bool addHeading(Logger &logger, Handle<Document> doc,
+ Handle<StructuredEntity> parent, const std::string &text)
{
// Add the heading.
- Rooted<StructuredEntity> heading = StructuredEntity::buildEntity(
- parent, doms, "heading", "heading", {}, "");
+ Rooted<StructuredEntity> heading = buildStructuredEntity(
+ doc, logger, parent, {"heading"}, "heading", {}, "");
if (heading.isNull()) {
return false;
}
// Add its text.
- if (!addText(heading, doms, text)) {
+ if (!addText(logger, doc, heading, text)) {
return false;
}
return true;
@@ -167,25 +168,25 @@ static bool addHeading(Handle<StructuredEntity> parent,
static int annoIdx = 1;
// Only works for non-overlapping annotations!
-static bool addAnnotation(Handle<Document> doc, Handle<StructuredEntity> parent,
- std::vector<Handle<Domain>> &doms,
+static bool addAnnotation(Logger &logger, Handle<Document> doc,
+ Handle<StructuredEntity> parent,
const std::string &text, const std::string &annoClass)
{
Rooted<AnnotationEntity::Anchor> start =
- AnnotationEntity::buildAnchor(parent, std::to_string(annoIdx++));
+ buildAnchor(logger, parent, std::to_string(annoIdx++));
if (start.isNull()) {
return false;
}
- if (!addText(parent, doms, text)) {
+ if (!addText(logger, doc, parent, text)) {
return false;
}
Rooted<AnnotationEntity::Anchor> end =
- AnnotationEntity::buildAnchor(parent, std::to_string(annoIdx++));
+ buildAnchor(logger, parent, std::to_string(annoIdx++));
if (end.isNull()) {
return false;
}
Rooted<AnnotationEntity> anno =
- AnnotationEntity::buildEntity(doc, doms, annoClass, start, end);
+ buildAnnotationEntity(doc, logger, {annoClass}, start, end);
if (anno.isNull()) {
return false;
}
@@ -197,34 +198,34 @@ static bool addAnnotation(Handle<Document> doc, Handle<StructuredEntity> parent,
* domain but also headings, emphasis and lists.
* TODO: insert emphasis and lists.
*/
-static Rooted<Document> constructAdvancedDocument(Manager &mgr,
+static Rooted<Document> constructAdvancedDocument(Manager &mgr, Logger &logger,
Handle<Domain> bookDom,
Handle<Domain> headingDom,
- Handle<Domain> listDom)
+ Handle<Domain> listDom,
+ Handle<Domain> emphasisDom)
{
- std::vector<Handle<Domain>> doms{bookDom, headingDom, listDom};
-
// Start with the (empty) document.
Rooted<Document> doc{new Document(mgr, "kant_was_ist_aufklaerung.oxd")};
+ doc->addDomains({bookDom, headingDom, listDom, emphasisDom});
// Add the root.
Rooted<StructuredEntity> book =
- StructuredEntity::buildRootEntity(doc, doms, "book");
+ buildRootStructuredEntity(doc, logger, {"book"});
if (book.isNull()) {
return {nullptr};
}
// Add the heading.
{
- Rooted<StructuredEntity> heading = StructuredEntity::buildEntity(
- book, doms, "heading", "heading", {}, "");
+ Rooted<StructuredEntity> heading = buildStructuredEntity(
+ doc, logger, book, {"heading"}, "heading", {}, "");
if (heading.isNull()) {
return {nullptr};
}
- if (!addText(heading, doms, "Beantwortung der Frage: ")) {
+ if (!addText(logger, doc, heading, "Beantwortung der Frage: ")) {
return {nullptr};
}
- if (!addAnnotation(doc, heading, doms, "Was ist Aufklärung?",
+ if (!addAnnotation(logger, doc, heading, "Was ist Aufklärung?",
"emphasized")) {
return {nullptr};
}
@@ -232,58 +233,57 @@ static Rooted<Document> constructAdvancedDocument(Manager &mgr,
// Add the main section.
Rooted<StructuredEntity> sec =
- StructuredEntity::buildEntity(book, doms, "section");
+ buildStructuredEntity(doc, logger, book, {"section"});
if (sec.isNull()) {
return {nullptr};
}
// Add the heading.
- if (!addHeading(sec, doms, "Was ist Aufklärung?")) {
+ if (!addHeading(logger, doc, sec, "Was ist Aufklärung?")) {
return {nullptr};
}
// Add paragraph with main text.
{
Rooted<StructuredEntity> p =
- StructuredEntity::buildEntity(sec, doms, "paragraph");
+ buildStructuredEntity(doc, logger, sec, {"paragraph"});
if (p.isNull()) {
return {nullptr};
}
// Add its text.
{
- if (!addAnnotation(doc, p, doms,
+ if (!addAnnotation(logger, doc, p,
"Aufklärung ist der Ausgang des Menschen aus "
"seiner selbstverschuldeten Unmündigkeit",
"strong")) {
return {nullptr};
}
- if (!addAnnotation(doc, p, doms, "Unmündigkeit",
- "emphasized")) {
+ if (!addAnnotation(logger, doc, p, "Unmündigkeit", "emphasized")) {
return {nullptr};
}
- if (!addText(p, doms,
+ if (!addText(logger, doc, p,
"ist das Unvermögen, sich seines Verstandes ohne "
"Leitung eines anderen zu bedienen. ")) {
return {nullptr};
}
- if (!addAnnotation(doc, p, doms, "Selbstverschuldet",
+ if (!addAnnotation(logger, doc, p, "Selbstverschuldet",
"emphasized")) {
return {nullptr};
}
- if (!addText(p, doms,
+ if (!addText(logger, doc, p,
" ist diese Unmündigkeit, wenn die Ursache derselben "
"nicht am Mangel des Verstandes, sondern der "
"Entschließung und des Mutes liegt, sich seiner ohne "
"Leitung eines andern zu bedienen.")) {
return {nullptr};
}
- if (!addAnnotation(doc, p, doms,
+ if (!addAnnotation(logger, doc, p,
"Sapere aude! Habe Mut, dich deines eigenen "
"Verstandes zu bedienen!",
"emphasized")) {
return {nullptr};
}
- if (!addText(p, doms,
+ if (!addText(logger, doc, p,
" ist also der Wahlspruch der Aufklärung.")) {
return {nullptr};
}
@@ -292,20 +292,18 @@ static Rooted<Document> constructAdvancedDocument(Manager &mgr,
// Add the "Lesarten" section
Rooted<StructuredEntity> lesarten =
- StructuredEntity::buildEntity(book, doms, "section");
+ buildStructuredEntity(doc, logger, book, {"section"});
if (lesarten.isNull()) {
return {nullptr};
}
// Add the heading.
- if (!addHeading(lesarten, doms, "Lesarten")) {
+ if (!addHeading(logger, doc, lesarten, "Lesarten")) {
return {nullptr};
}
// Add list with citations
{
- // TODO: We need to restrict this to the list domain. Otherwise
- // this leads to resolve errors for some reason.
Rooted<StructuredEntity> ul =
- StructuredEntity::buildEntity(lesarten, {listDom}, "ul");
+ buildStructuredEntity(doc, logger, lesarten, {"ul"});
if (ul.isNull()) {
return {nullptr};
}
@@ -323,13 +321,12 @@ static Rooted<Document> constructAdvancedDocument(Manager &mgr,
"von F. Ch. Starke. 2 Bände. Leipzig 1833 und Quedlinburg 1838. "
"Bd. I, S. 75–84."};
for (auto &cit : citations) {
- // TODO: This needs to be restricted as well.
Rooted<StructuredEntity> item =
- StructuredEntity::buildEntity(ul, {listDom}, "item");
+ buildStructuredEntity(doc, logger, ul, {"item"});
if (item.isNull()) {
return {nullptr};
}
- if (!addText(item, doms, cit)) {
+ if (!addText(logger, doc, item, cit)) {
return {nullptr};
}
}
diff --git a/test/core/model/TestDocument.hpp b/test/core/model/TestDocument.hpp
index 6b0267a..eaec42c 100644
--- a/test/core/model/TestDocument.hpp
+++ b/test/core/model/TestDocument.hpp
@@ -23,6 +23,8 @@
#include <core/model/Domain.hpp>
#include <core/model/Typesystem.hpp>
+#include "TestDocumentBuilder.hpp"
+
namespace ousia {
namespace model {
@@ -30,57 +32,58 @@ namespace model {
* This constructs a fairly simple test document for the "book" domain. The
* structure of the document can be seen in the Code below.
*/
-static Rooted<Document> constructBookDocument(Manager &mgr,
+static Rooted<Document> constructBookDocument(Manager &mgr, Logger &logger,
Rooted<Domain> bookDomain)
{
// Start with the (empty) document.
Rooted<Document> doc{new Document(mgr, "myDoc.oxd")};
+ doc->addDomain(bookDomain);
// Add the root.
Rooted<StructuredEntity> root =
- StructuredEntity::buildRootEntity(doc, {bookDomain}, "book");
+ buildRootStructuredEntity(doc, logger, {"book"});
if (root.isNull()) {
return {nullptr};
}
// Add a paragraph.
Rooted<StructuredEntity> foreword =
- StructuredEntity::buildEntity(root, {bookDomain}, "paragraph");
+ buildStructuredEntity(doc, logger, root, {"paragraph"});
if (foreword.isNull()) {
return {nullptr};
}
// Add its text.
Rooted<StructuredEntity> foreword_text =
- StructuredEntity::buildEntity(foreword, {bookDomain}, "text");
+ buildStructuredEntity(doc, logger, foreword, {"text"});
if (foreword_text.isNull()) {
return {nullptr};
}
// And its primitive content
Variant text{"Some introductory text"};
Rooted<DocumentPrimitive> foreword_primitive =
- DocumentPrimitive::buildEntity(foreword_text, text, "content");
+ buildPrimitiveEntity(logger, foreword_text, text, "content");
if (foreword_primitive.isNull()) {
return {nullptr};
}
// Add a section.
Rooted<StructuredEntity> section =
- StructuredEntity::buildEntity(root, {bookDomain}, "section");
+ buildStructuredEntity(doc, logger, root, {"section"});
// Add a paragraph for it.
Rooted<StructuredEntity> main =
- StructuredEntity::buildEntity(section, {bookDomain}, "paragraph");
+ buildStructuredEntity(doc, logger, section, {"paragraph"});
if (main.isNull()) {
return {nullptr};
}
// Add its text.
Rooted<StructuredEntity> main_text =
- StructuredEntity::buildEntity(main, {bookDomain}, "text");
+ buildStructuredEntity(doc, logger, main, {"text"});
if (main_text.isNull()) {
return {nullptr};
}
// And its primitive content
text = Variant{"Some actual text"};
Rooted<DocumentPrimitive> main_primitive =
- DocumentPrimitive::buildEntity(main_text, text, "content");
+ buildPrimitiveEntity(logger, main_text, text, "content");
if (main_primitive.isNull()) {
return {nullptr};
}
diff --git a/test/core/model/TestDocumentBuilder.hpp b/test/core/model/TestDocumentBuilder.hpp
new file mode 100644
index 0000000..0c6ca34
--- /dev/null
+++ b/test/core/model/TestDocumentBuilder.hpp
@@ -0,0 +1,300 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _MODEL_TEST_DOCUMENT_BUILDER_HPP_
+#define _MODEL_TEST_DOCUMENT_BUILDER_HPP_
+
+#include <sstream>
+
+#include <core/common/Logger.hpp>
+#include <core/model/Document.hpp>
+#include <core/model/Domain.hpp>
+#include <core/model/Typesystem.hpp>
+
+namespace ousia {
+namespace model {
+
+typedef std::vector<std::string> Path;
+
+/* Class StructuredEntity */
+
+static std::string getPathString(const Path &path)
+{
+ std::stringstream ss;
+ ss << path[0];
+ for (size_t i = 1; i < path.size(); i++) {
+ ss << '.';
+ ss << path[i];
+ }
+ return std::move(ss.str());
+}
+
+static Rooted<Descriptor> resolveDescriptor(Handle<Document> doc,
+ Logger &logger, const Path &path,
+ const RttiBase &type)
+{
+ // use the actual resolve method.
+ std::vector<ResolutionResult> resolved = doc->resolve(path, type);
+ // if we don't find anything, log an error
+ if (resolved.size() == 0) {
+ logger.error(std::string("Could not resolve ") + getPathString(path));
+ return {nullptr};
+ }
+ // if we have more than one result, log an error.
+ if (resolved.size() > 1) {
+ logger.error(getPathString(path) + " was ambigous: ");
+ for (auto &r : resolved) {
+ logger.error(getPathString(r.node->path()));
+ }
+ }
+ // Return the resulting node.
+ return resolved[0].node.cast<Descriptor>();
+}
+
+/**
+ * This builds the root StructuredEntity for the given document. It
+ * automatically appends the newly build entity to the given document.
+ *
+ * @param document is the document this entity shall be build for. The
+ * resulting entity will automatically be appended to that
+ * document. Also the manager of that document will be
+ * used to register the new node.
+ * @param logger is the current logger.
+ * @param path is the name of the StructuredClass or a path specifying it
+ * uniquely.
+ * @param attributes are the attributes of the new node in terms of a Struct
+ * variant (empty per default).
+ * @param name is the name of this StructuredEntity (empty per
+ * default).
+ * @return the newly created StructuredEntity or a nullptr if some
+ * input handle was empty or the given domains did not
+ * contain a StructuredClass with the given name.
+ */
+Rooted<StructuredEntity> buildRootStructuredEntity(Handle<Document> document,
+ Logger &logger,
+ const Path &path,
+ Variant attributes = {},
+ std::string name = "")
+{
+ // If the parent is not set, we can not build the entity.
+ if (document == nullptr) {
+ logger.error("The input document handle was null!");
+ return {nullptr};
+ }
+ // If we can not find the correct descriptor, we can not build the entity
+ // either.
+ Rooted<Descriptor> descriptor =
+ resolveDescriptor(document, logger, path, RttiTypes::StructuredClass);
+ if (descriptor == nullptr) {
+ return {nullptr};
+ }
+ // Then construct the StructuredEntity itself.
+ Rooted<StructuredEntity> root{new StructuredEntity(
+ document->getManager(), document, descriptor.cast<StructuredClass>(),
+ attributes, std::move(name))};
+ // append it to the document.
+ document->setRoot(root);
+ // and return it.
+ return root;
+}
+
+/**
+ * This builds a StructuredEntity as child of the given DocumentEntity. It
+ * automatically appends the newly build entity to its parent.
+ *
+ * @param document is the document this entity shall be build for. The domains
+ * referenced here are the basis to resolve the given path.
+ * @param logger is the current logger.
+ * @param parent is the parent DocumentEntity. The newly constructed
+ * StructuredEntity will automatically be appended to it.
+ * @param path is the name of the StructuredClass or a path specifying it
+ * uniquely.
+ * @param fieldName is the name of the field where the newly constructed
+ * StructuredEntity shall be appended.
+ * @param attributes are the attributes of the new node in terms of a Struct
+ * variant (empty per default).
+ * @param name is the name of this StructuredEntity (empty per
+ * default).
+ * @return the newly created StructuredEntity or a nullptr if some
+ * input handle was empty or the given domains did not
+ * contain a StructuredClass with the given name.
+ */
+Rooted<StructuredEntity> buildStructuredEntity(
+ Handle<Document> document, Logger &logger, Handle<DocumentEntity> parent,
+ Path path, const std::string &fieldName = "", Variant attributes = {},
+ std::string name = "")
+{
+ // If the input handles are not set, we can not build the entity.
+ if (parent == nullptr) {
+ logger.error("The input parent handle was null!");
+ return {nullptr};
+ }
+ if (document == nullptr) {
+ logger.error("The input document handle was null!");
+ return {nullptr};
+ }
+ // If we can not find the correct descriptor, we can not build the entity
+ // either.
+ Rooted<Descriptor> descriptor =
+ resolveDescriptor(document, logger, path, RttiTypes::StructuredClass);
+ if (descriptor == nullptr) {
+ return {nullptr};
+ }
+ // Then construct the StructuredEntity itself.
+ Rooted<StructuredEntity> entity{new StructuredEntity(
+ parent->getManager(), parent, descriptor.cast<StructuredClass>(),
+ attributes, std::move(name))};
+ // if the field does not exist, return null handle as well.
+ if (!parent->hasField(fieldName)) {
+ logger.error(std::string("The parent has no field of the name ") +
+ fieldName + "!");
+ return {nullptr};
+ }
+ NodeVector<StructuredEntity> &field = parent->getField(fieldName);
+ field.push_back(entity);
+
+ // and return it.
+ return entity;
+}
+
+/**
+ * This builds a DocumentPrimitive as child of the given DocumentEntity. It
+ * automatically appends the newly build entity to its parent.
+ *
+ * @param logger is the current logger.
+ * @param parent is the parent DocumentEntity. The newly constructed
+ * DocumentPrimitive will automatically be appended to it.
+ * @param content is the primitive content of the new node in terms of a
+ * Struct variant.
+ * @param fieldName is the name of the field where the newly constructed
+ * StructuredEntity shall be appended.
+ *
+ * @return the newly created DocumentPrimitive or a nullptr if some
+ * input handle was empty.
+ */
+Rooted<DocumentPrimitive> buildPrimitiveEntity(
+ Logger &logger, Handle<DocumentEntity> parent, Variant content = {},
+ const std::string &fieldName = "")
+{
+ // If the input handles are not set, we can not build the entity.
+ if (parent == nullptr) {
+ logger.error("The input parent handle was null!");
+ return {nullptr};
+ }
+ // Then construct the StructuredEntity itself.
+ Rooted<DocumentPrimitive> entity{
+ new DocumentPrimitive(parent->getManager(), parent, content)};
+ // if the field does not exist, return null handle as well.
+ if (!parent->hasField(fieldName)) {
+ logger.error(std::string("The parent has no field of the name ") +
+ fieldName + "!");
+ return {nullptr};
+ }
+ NodeVector<StructuredEntity> &field = parent->getField(fieldName);
+ field.push_back(entity);
+ // and return it.
+ return entity;
+}
+
+/**
+ * This builds an Anchor as child of the given DocumentEntity. It
+ * automatically appends the newly build Anchor to its parent.
+ *
+ * @param logger is the current logger.
+ * @param parent is the parent DocumentEntity. The newly constructed
+ * Anchor will automatically be appended to it.
+ * @param id is the id of this Anchor.
+ * @param fieldName is the name of the field where the newly constructed
+ * Anchor shall be appended.
+ *
+ * @return the newly created Anchor or a nullptr if some
+ * input handle was empty.
+ */
+Rooted<AnnotationEntity::Anchor> buildAnchor(Logger &logger,
+ Handle<DocumentEntity> parent,
+ std::string id,
+ const std::string &fieldName = "")
+{
+ // If the parent is not set, we can not build the anchor.
+ if (parent == nullptr) {
+ logger.error("The input parent handle was null!");
+ return {nullptr};
+ }
+ // Then construct the Anchor itself
+ Rooted<AnnotationEntity::Anchor> anchor{
+ new AnnotationEntity::Anchor(parent->getManager(), parent, id)};
+ // append the new entity to the right field.
+ if (!parent->hasField(fieldName)) {
+ logger.error(std::string("The parent has no field of the name ") +
+ fieldName + "!");
+ return {nullptr};
+ }
+ NodeVector<StructuredEntity> &field = parent->getField(fieldName);
+ field.push_back(anchor);
+ // and return it.
+ return anchor;
+}
+/**
+ * This builds an AnnotationEntity as child of the given Document. It
+ * automatically appends the newly build entity to its parent.
+ *
+ * @param document is the document this entity shall be build for. The domains
+ * referenced here are the basis to resolve the given path.
+ * @param logger is the current logger.
+ * @param path is the name of the AnnotationClass or a path specifying it
+ * uniquely.
+ * @param start is the start Anchor for this AnnotationEntity.
+ * @param end is the end Anchor for this AnnotationEntity.
+ * @param attributes are the attributes of the new node in terms of a Struct
+ * variant (empty per default).
+ * @param name is the name of this AnnotationEntity (empty per
+ * default).
+ * @return the newly created AnnotationEntity or a nullptr if some
+ * input handle was empty or the given domains did not
+ * contain a AnnotationClass with the given name.
+ */
+Rooted<AnnotationEntity> buildAnnotationEntity(
+ Handle<Document> document, Logger &logger, const Path &path,
+ Handle<AnnotationEntity::Anchor> start,
+ Handle<AnnotationEntity::Anchor> end, Variant attributes = {},
+ std::string name = "")
+{
+ // If the input handles are not set, we can not build the entity.
+ if (document == nullptr) {
+ logger.error("The input document handle was null!");
+ return {nullptr};
+ }
+ // If we can not find the correct descriptor, we can not build the
+ // entity either.
+ Rooted<Descriptor> descriptor =
+ resolveDescriptor(document, logger, path, RttiTypes::AnnotationClass);
+ if (descriptor == nullptr) {
+ return {nullptr};
+ }
+ // Then construct the AnnotationEntity itself
+ Rooted<AnnotationEntity> anno{new AnnotationEntity(
+ document->getManager(), document, descriptor.cast<AnnotationClass>(),
+ attributes, start, end, name)};
+ // append the new entity to the document
+ document->getAnnotations().push_back(anno);
+ // and return it.
+ return anno;
+}
+}
+}
+#endif
diff --git a/test/plugins/html/DemoOutputTest.cpp b/test/plugins/html/DemoOutputTest.cpp
index 36b53b4..4ab2c53 100644
--- a/test/plugins/html/DemoOutputTest.cpp
+++ b/test/plugins/html/DemoOutputTest.cpp
@@ -26,7 +26,6 @@
#include <core/model/Domain.hpp>
#include <core/model/TestAdvanced.hpp>
-#include <core/model/TestDocument.hpp>
#include <core/model/TestDomain.hpp>
namespace ousia {
@@ -35,7 +34,7 @@ namespace html {
TEST(DemoHTMLTransformer, writeHTML)
{
// Construct Manager
- Logger logger;
+ TerminalLogger logger{std::cerr, true};
Manager mgr{1};
Rooted<model::SystemTypesystem> sys{new model::SystemTypesystem(mgr)};
// Get the domains.
@@ -48,8 +47,8 @@ TEST(DemoHTMLTransformer, writeHTML)
Rooted<model::Domain> emDom =
model::constructEmphasisDomain(mgr, sys, logger);
// Construct the document.
- Rooted<model::Document> doc =
- model::constructAdvancedDocument(mgr, bookDom, headingDom, listDom);
+ Rooted<model::Document> doc = model::constructAdvancedDocument(
+ mgr, logger, bookDom, headingDom, listDom, emDom);
#ifdef MANAGER_GRAPHVIZ_EXPORT
// dump the manager state