From dd3e14ec4dd2386cc8af61157975118acb4d6ee2 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Sun, 4 Jan 2015 12:31:36 +0100 Subject: improved documentation. --- src/core/model/Document.hpp | 64 +++++++++--- src/core/model/Domain.hpp | 229 ++++++++++++++++++++++++++++++------------ src/plugins/css/CSSParser.hpp | 10 +- 3 files changed, 223 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index 2d792c5..6ca1a30 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -32,21 +32,33 @@ * Structure Nodes, effectively resulting in a Document Graph instead of a * Document Tree (other references may introduce cycles as well). * - * Consider this simplified XML representation of a document (TODO: Use - * non-simplified XML as soon as possible): + * Consider this XML representation of a document using the "book" domain: * - * - * - * - * - * This is some text with some emphasized and - * strong text. - * - * - * - * - * - * + * + * + * + * + * + * + * + * This might be some introductory text or a dedication. Ideally, of + * course, such elements would be semantically specified as such in + * additional domains (or in this one). + * + * Here we might have an introduction to the chapter, including some + * overview of the chapters structure. + *
+ * Here we might find the actual section content. + *
+ *
+ * Here we might find the actual section content. + * + * + * And there might even be another paragraph. + *
+ *
+ *
+ *
* * As can be seen the StructureEntities inherently follow a tree structure that * is restricted by the implicit context free grammar of the "book" Domain @@ -56,12 +68,32 @@ * Another interesting fact is the special place of AnnotationEntities: They are * Defined by start and end Anchors in the text. Note that this allows for * overlapping annotations and provides a more intuitive (and semantically - * sound) handling of such span-like concepts. + * sound) handling of such span-like concepts. So the + * + * content + * + * is implicitly expanded to: + * + * content + * + * * Note that the place of an AnnotationEntity within the XML above is not * strictly defined. It might as well be placed as a child of the "book" node. * In general it is recommended to use the lowest possible place in the * StructureTree to include the AnnotationEntity for better readability. * + * Also note that text content like + * + * Here we might find the actual section content. + * + * is implicitly expanded using transparency to: + * + * + * + * Here we might find the actual section content. + * + * + * * @author Benjamin Paaßen (bpaassen@techfak.uni-bielefeld.de) */ @@ -365,7 +397,7 @@ public: */ class Document : public Node { private: - //TODO: Might there be several roots? E.g. metadata? + // TODO: Might there be several roots? E.g. metadata? Owned root; public: diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index cd74a19..7e4e9f7 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -30,24 +30,65 @@ * terms "StructuredClass" and "FieldDescriptor". * On the top level you would start with a StructuredClass, say "book", which * in turn might contain two FieldDescriptors, one for the meta data of ones - * book and one for the actual structure. Consider the following (simplified) - * XML notation (TODO: Use a non-simplified notation as soon as the format is - * clear.) - * - * - * - * - * Here we would reference the possible child classes, e.g. section, - * paragraph, etc. - * - * - * - * - * Here we would reference the possible child classes for meta, - * information, e.g. authors, date, version, etc. - * - * - * + * book and one for the actual structure. Consider the following XML: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * * * Note that we define one field as the TREE (meaning the main or default * document structure) and one mearly as SUBTREE, relating to supporting @@ -58,11 +99,19 @@ * TREE field and at least one permitted child must exist, either primitive or * as another StructuredClass. * - * The translation to context free grammars is roughly as follows: + * The translation to context free grammars is as follows: * - * BOOK := book BOOK_STRUCTURE BOOK_META - * BOOK_STRUCTURE := SECTION BOOK_STRUCTURE | PARAGRAPH BOOK_STRUCTURE | epsilon - * BOOK_META := AUTHOR BOOK_META | DATE BOOK_META + * BOOK := BOOK_TREE + * BOOK_TREE := CHAPTER BOOK_TREE | PARAGRAPH BOOK_TREE | epsilon + * CHAPTER := CHAPTER_TREE + * CHAPTER_TREE := SECTION CHAPTER_TREE | PARAGRAPH CHAPTER_TREE | epsilon + * SECTION :=
SECTION_TREE
+ * SECTION_TREE := SUBSECTION SECTION_TREE | PARAGRAPH SECTION_TREE | + * epsilon + * SUBSECTION := SUBSECTION_TREE + * SUBSECTION_TREE := PARAGRAPH SUBSECTION_TREE | epsilon + * PARAGRAPH := PARAGRAPH_CONTENT + * PARAGRAPH_CONTENT := string * * Note that this translation recurs to further nonterminals like SECTION but * necessarily produces one "book" terminal. Also note that, in principle, @@ -70,11 +119,72 @@ * the proper StructuredClass. This can be regulated by the "cardinality" * property of a StructuredClass. * + * It is possible to add further fields, like we would in the "headings" domain + * to add titles to our structure. + * + * + * + * + * + * + * + * + * + * + * + * ... + * + * + * + * + * + * + * + * This would change the context free grammar as follows: + * + * BOOK := HEADING BOOK_TREE + * HEADING := PARAGRAPH + * * AnnotationClasses on the other hand do not specify a context free grammar. * They merely specify what kinds of Annotations are allowed within this domain * and which fields or attributes they have. Note that Annotations are allowed * to define structured children that manifest e.g. meta information of that - * Annotation. + * Annotation. An example for that would be the "comment" domain: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * Here we have comment annotations, which have a reply tree as sub structure. * * @author Benjamin Paaßen (bpaassen@techfak.uni-bielefeld.de) */ @@ -105,13 +215,17 @@ class Domain; * Hierarchy. * * As an example consider the "paragraph" StructuredClass, which might allow - * the actual text content. Here is the according simplified XML (TODO: replace - * with a non-simplified version as soon as the XML syntax is clear.) + * the actual text content. Here is the according XML: * - * - * - * + * + * + * + * + * + * + * + * + * * * Accordingly the primitiveType field of a FieldDescriptor may only be * defined if the type is set to "PRIMITIVE". If the type is something else @@ -286,36 +400,28 @@ typedef RangeSet Cardinality; * consult the Header documentation above. * * Note that a StructuredClass may "invade" an existing Domain description by - * defining itself as a viable child in one existing field. Consider a "section" - * StructuredClass (continuing the example in the header documentation): - * - * - * - * - * paragraph - * - * - * - * - * Of course in most cases we do not only want to allow paragraphs inside - * sections, but also (for example) lists. How would one add that - * without manipulating the existing domain or having to define an entirely - * new domain in which section allows for lists? - * - * Our solution to this problem is the parent mechanism. The simplified XML - * (TODO: Use non-simplified version as soon as possible) for the "list" - * StructuredClass would look like this: - * - * - * - * - * item - * - * - * - * section.structure - * - * + * defining itself as a viable child in one existing field. Consider the + * example of the "heading" domain from the header documentation again: + * + * + * + * + * + * + * + * + * + * + * + * ... + * + * + * + * + * + * + * + * The "parent" construct allows to "invade" another domain. * * This does indeed interfere with an existing domain and one must carefully * craft such parent references to not create undesired side effects. However @@ -404,8 +510,7 @@ public: Handle attributesDescriptor = nullptr, // TODO: What would be a wise default value for isa? Handle isa = nullptr, - bool transparent = false, - bool root = false) + bool transparent = false, bool root = false) : Descriptor(mgr, std::move(name), domain, attributesDescriptor), cardinality(cardinality), isa(acquire(isa)), @@ -497,9 +602,7 @@ extern const Rtti Descriptor; extern const Rtti StructuredClass; extern const Rtti AnnotationClass; extern const Rtti Domain; - } - } #endif /* _OUSIA_MODEL_DOMAIN_HPP_ */ diff --git a/src/plugins/css/CSSParser.hpp b/src/plugins/css/CSSParser.hpp index 6d84dbf..1ec54f5 100644 --- a/src/plugins/css/CSSParser.hpp +++ b/src/plugins/css/CSSParser.hpp @@ -15,7 +15,15 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ - +/** + * @file CSSParser.hpp + * + * Contains the classes needed to transform a CSS string to a CSS SelectorTree + * with attached RuleSets. The details are explained in the class + * documentations. + * + * @author Benjamin Paassen - bpaassen@techfak.uni-bielefeld.de + */ #ifndef _OUSIA_CSS_PARSER_HPP_ #define _OUSIA_CSS_PARSER_HPP_ -- cgit v1.2.3 From 1f4b48537f52646f9e4d520c2b2c2425f3565fa2 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Sun, 4 Jan 2015 17:41:53 +0100 Subject: first draft for HTML Demo Output (still a lot of todos). --- CMakeLists.txt | 8 ++ src/plugins/html/DemoOutput.cpp | 187 ++++++++++++++++++++++++++++++++++++++++ src/plugins/html/DemoOutput.hpp | 85 ++++++++++++++++++ 3 files changed, 280 insertions(+) create mode 100644 src/plugins/html/DemoOutput.cpp create mode 100644 src/plugins/html/DemoOutput.hpp (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a494c3..ddb087e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,14 @@ TARGET_LINK_LIBRARIES(ousia_css ousia_core ) +ADD_LIBRARY(ousia_html + src/plugins/html/DemoOutput +) + +TARGET_LINK_LIBRARIES(ousia_html + ousia_core +) + ADD_LIBRARY(ousia_xml src/plugins/xml/XmlParser ) diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp new file mode 100644 index 0000000..6b9b3a4 --- /dev/null +++ b/src/plugins/html/DemoOutput.cpp @@ -0,0 +1,187 @@ +/* + 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 "DemoOutput.hpp" + +namespace ousia { +namespace html { + +void DemoHTMLTransformer::writeHTML(Handle doc, + std::ostream &out) +{ + // write preamble + out << "\n"; + out << "\n"; + out << "\t\n"; + out << "\t\tTest HTML Output for" << doc->getName() << "\n"; + out << "\t\n"; + out << "\t\n"; + + // look for the book root node. + Rooted 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\n"; + out << "\n"; +} + +/** + * This is just for easier internal handling. + */ +enum class SectionType { BOOK, CHAPTER, SECTION, SUBSECTION, NONE }; + +SectionType getSectionType(const std::string &name) +{ + if (name == "book") { + return SectionType::BOOK; + } else if (name == "chapter") { + return SectionType::CHAPTER; + } else if (name == "section") { + return SectionType::SECTION; + } else if (name == "subsection") { + return SectionType::SUBSECTION; + } else { + return SectionType::NONE; + } +} + +void DemoHTMLTransformer::writeSection(Handle sec, + std::ostream &out) +{ + // check the section type. + SectionType type = getSectionType(sec->getDescriptor()->getName()); + if (type == SectionType::NONE) { + // if the input node is no section, we ignore it. + return; + } + // get the fields. + std::vector> &fields = sec->getFields(); + // check if we have a heading. + if (fields.size() > 1 && fields[1].size() > 0) { + out << "\t\t"; + switch (type) { + case SectionType::BOOK: + out << "

"; + break; + case SectionType::CHAPTER: + out << "

"; + break; + case SectionType::SECTION: + out << "

"; + break; + case SectionType::SUBSECTION: + out << "

"; + break; + case SectionType::NONE: + // this can not happen; + break; + } + // the second field marks the heading. So let's write it. + writeParagraph(fields[1][0], out, false); + // close the heading tag. + switch (type) { + case SectionType::BOOK: + out << "

"; + break; + case SectionType::CHAPTER: + out << ""; + break; + case SectionType::SECTION: + out << ""; + break; + case SectionType::SUBSECTION: + out << ""; + break; + case SectionType::NONE: + // this can not happen; + break; + } + out << "\n"; + } + + // then write the section content recursively. + for (auto &n : fields[0]) { + /* + * 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. + */ + std::string childDescriptorName = n->getDescriptor()->getName(); + if (childDescriptorName == "paragraph") { + writeParagraph(n, out); + // TODO: Implement + // } else if(childDescriptorName == "ul"){ + // writeList(n, out); + } else { + writeSection(n, out); + } + } +} + +void DemoHTMLTransformer::writeParagraph(Handle par, + std::ostream &out, bool writePTags) +{ + // validate descriptor. + if (par->getDescriptor()->getName() != "paragraph") { + throw OusiaException("Expected paragraph!"); + } + // get the fields. + std::vector> &fields = par->getFields(); + // write heading if its there. + // check if we have a heading. + if (fields.size() > 1 && fields[1].size() > 0) { + // start the heading tag + out << "\t\t
"; + // the second field marks the heading. So let's write it. + writeParagraph(fields[1][0], out, false); + // close the heading tag. + out << "
\n"; + } + // write start tag + if (writePTags) { + out << "\t\t

"; + } + // write content + // TODO: What about emphasis? + for (auto &text : fields[0]) { + if (text->getDescriptor()->getName() != "text") { + throw OusiaException("Expected text!"); + } + Handle primitive = + text->getFields()[0][0].cast(); + if (primitive == nullptr) { + throw OusiaException("Text field is not primitive!"); + } + out << primitive->getContent().asString(); + } + // write end tag + if (writePTags) { + out << "

\n"; + } +} +} +} diff --git a/src/plugins/html/DemoOutput.hpp b/src/plugins/html/DemoOutput.hpp new file mode 100644 index 0000000..ca9bcd2 --- /dev/null +++ b/src/plugins/html/DemoOutput.hpp @@ -0,0 +1,85 @@ +/* + 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 . +*/ + +/** + * @file DemoOutput.hpp + * + * This implements a Demo HTML output for the following domains: + * * book + * * headings + * * emphasis + * * lists + * + * @author Benjamin Paassen - bpaassen@techfak.uni-bielefeld.de + */ +#ifndef _OUSIA_HTML_DEMO_OUTPUT_HPP_ +#define _OUSIA_HTML_DEMO_OUTPUT_HPP_ + +#include + +#include + +namespace ousia { +namespace html { + +class DemoHTMLTransformer { +private: + /** + * This method is to be called recursively to write a chapter, section or + * subsection to HTML. + */ + void writeSection(Handle sec, std::ostream& out); + /** + * This method is to be called recursively to write a paragraph to HTML. + */ + void writeParagraph(Handle par, std::ostream& out, + bool writePTags = true); + /** + * This method is to be called recursively to write a list to HTML. + * TODO: Implement + */ +// void writeList(Handle sec, std::ostream& out, +// int tabdepth); + + //TODO: Implement emphasis. + +public: + /** + * This writes a HTML representation of the given document to the given + * output stream. Note that this method lacks the generality of our Ousia + * approach with respect to two important points: + * 1.) It hardcodes the dependency to a certain set of domains in the C++ + * code. + * 2.) It does not use the proposed pipeline of first copying the document + * graph, then attaching style attributes and then transforming it to a + * specific output format but does all of these steps at once. + * 3.) It does not use different transformers for the different domains but + * does all transformations at once. + * Therefore this is not an adequate model of our algorithms but only a + * Demo. + * + * @param doc is a Document using concepts of the book, headings, emphasis + * and lists domains but no other. + * @param out is the output stream the data shall be written to. + */ + void writeHTML(Handle doc, std::ostream& out); +}; +} +} + +#endif -- cgit v1.2.3 From 7d22aac0c7be52381822abdd0cb6860deaf01096 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Sun, 4 Jan 2015 19:30:56 +0100 Subject: fixed a nasty bug in the getField method of DocumentEntity. Also corrected some issues in the TestDocument and TestDomain. --- src/core/model/Document.cpp | 20 ++++++------- src/core/model/Document.hpp | 33 ++++++--------------- test/core/model/DocumentTest.cpp | 62 +++++++++++++++++++++++++++++++++++++++- test/core/model/TestDocument.hpp | 26 +++++++++++------ test/core/model/TestDomain.hpp | 15 ++++++++-- 5 files changed, 109 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 854e717..e5d0755 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -57,20 +57,22 @@ int DocumentEntity::getFieldDescriptorIndex(const std::string &fieldName) return -1; } -void DocumentEntity::getField(NodeVector &res, - const std::string &fieldName) +NodeVector &DocumentEntity::getField( + const std::string &fieldName) { int f = getFieldDescriptorIndex(fieldName); if (f < 0) { - NodeVector empty{this}; - res = NodeVector(this); + throw OusiaException("No field for the given name exists!"); } - res = fields[f]; + return fields[f]; } NodeVector &DocumentEntity::getField( - Rooted fieldDescriptor) + Handle fieldDescriptor) { + if(fieldDescriptor.isNull()){ + throw OusiaException("The given FieldDescriptor handle is null!"); + } const NodeVector &fds = descriptor->getFieldDescriptors(); int f = 0; for (auto &fd : fds) { @@ -155,8 +157,7 @@ Rooted StructuredEntity::buildEntity( return {nullptr}; } // append the new entity to the right field. - NodeVector field(parent); - parent->getField(field, fieldName); + NodeVector& field = parent->getField(fieldName); field.push_back(entity); // and return it. @@ -179,8 +180,7 @@ Rooted DocumentPrimitive::buildEntity( return {nullptr}; } // append the new entity to the right field. - NodeVector field(parent); - parent->getField(field, fieldName); + NodeVector& field = parent->getField(fieldName); field.push_back(entity); // and return it. diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index 6ca1a30..fabdcaf 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -155,12 +155,6 @@ public: Variant getAttributes() const { return attributes; } - /** - * This allows a direct manipulation of the internal data structure of a - * DocumentEntity and is not recommended. TODO: Delete this? - */ - std::vector> &getFields() { return fields; } - /** * This returns true if there is a FieldDescriptor in the Descriptor for * this DocumentEntity which has the given name. If an empty name is @@ -180,29 +174,18 @@ public: /** * This returns the vector of entities containing all members of the field - * for which the FieldDescriptor has the specified name. If an empty name is - * given it is assumed that the 'default' FieldDescriptor is referenced, - * where 'default' means either: + * with the given name. If an empty name is given it is assumed that the + * 'default' FieldDescriptor is referenced, where 'default' means either: * 1.) The only TREE typed FieldDescriptor (if present) or * 2.) the only FieldDescriptor (if only one is specified). * - * Note that the output of this method might well be ambigous: If no - * FieldDescriptor matches the given name an empty NodeVector is - * returned. This is also the case, however, if there are no members for an - * existing field. Therefore it is recommended to additionally check the - * output of "hasField" or use the version of this method with - * a FieldDescriptor as input. + * If the name is unknown an exception is thrown. * - * @param fieldName is the name of the field as specified in the + * @param fieldName is the name of a field as specified in the * FieldDescriptor in the Domain description. - * @param res is a NodeVector reference where the result will be - * stored. After using this method the reference will - * either refer to all StructuredEntities in that field. If - * the field is unknown or if no members exist in that - * field yet, the NodeVector will be empty. + * @return a NodeVector of all StructuredEntities in that field. */ - void getField(NodeVector &res, - const std::string &fieldName = ""); + NodeVector &getField(const std::string &fieldName = ""); /** * This returns the vector of entities containing all members of the field @@ -216,7 +199,7 @@ public: * @return a NodeVector of all StructuredEntities in that field. */ NodeVector &getField( - Rooted fieldDescriptor); + Handle fieldDescriptor); }; /** @@ -407,7 +390,7 @@ public: { } - void setRoot(Handle root) { root = acquire(root); }; + void setRoot(Handle root) { this->root = acquire(root); }; Rooted getRoot() const { return root; } }; diff --git a/test/core/model/DocumentTest.cpp b/test/core/model/DocumentTest.cpp index 9e3229c..a671d2c 100644 --- a/test/core/model/DocumentTest.cpp +++ b/test/core/model/DocumentTest.cpp @@ -37,8 +37,68 @@ TEST(Document, testDocumentConstruction) // Construct the document. Rooted doc = constructBookDocument(mgr, domain); - // If that works we are happy already. + // Check the document content. ASSERT_FALSE(doc.isNull()); + // get root node. + Rooted root = doc->getRoot(); + ASSERT_FALSE(root.isNull()); + ASSERT_EQ("book", root->getDescriptor()->getName()); + ASSERT_TRUE(root->hasField()); + ASSERT_EQ(2, root->getField().size()); + // get foreword (paragraph) + { + Rooted foreword = root->getField()[0]; + ASSERT_FALSE(foreword.isNull()); + ASSERT_EQ("paragraph", foreword->getDescriptor()->getName()); + // it should contain one text node + ASSERT_TRUE(foreword->hasField()); + ASSERT_EQ(1, foreword->getField().size()); + // which in turn should have a primitive content field containing the + // right text. + { + Rooted text = foreword->getField()[0]; + ASSERT_FALSE(text.isNull()); + ASSERT_EQ("text", text->getDescriptor()->getName()); + ASSERT_TRUE(text->hasField()); + ASSERT_EQ(1, text->getField().size()); + ASSERT_TRUE(text->getField()[0]->isa(typeOf())); + Variant content = + text->getField()[0].cast()->getContent(); + ASSERT_EQ("Some introductory text", content.asString()); + } + } + // get section + { + Rooted section = root->getField()[1]; + ASSERT_FALSE(section.isNull()); + ASSERT_EQ("section", section->getDescriptor()->getName()); + // it should contain one paragraph + ASSERT_TRUE(section->hasField()); + ASSERT_EQ(1, section->getField().size()); + { + Rooted par = section->getField()[0]; + ASSERT_FALSE(par.isNull()); + ASSERT_EQ("paragraph", par->getDescriptor()->getName()); + // it should contain one text node + ASSERT_TRUE(par->hasField()); + ASSERT_EQ(1, par->getField().size()); + // which in turn should have a primitive content field containing + // the + // right text. + { + Rooted text = par->getField()[0]; + ASSERT_FALSE(text.isNull()); + ASSERT_EQ("text", text->getDescriptor()->getName()); + ASSERT_TRUE(text->hasField()); + ASSERT_EQ(1, text->getField().size()); + ASSERT_TRUE( + text->getField()[0]->isa(typeOf())); + Variant content = + text->getField()[0].cast()->getContent(); + ASSERT_EQ("Some actual text", content.asString()); + } + } + } } } } diff --git a/test/core/model/TestDocument.hpp b/test/core/model/TestDocument.hpp index a1a3434..6b0267a 100644 --- a/test/core/model/TestDocument.hpp +++ b/test/core/model/TestDocument.hpp @@ -50,13 +50,18 @@ static Rooted constructBookDocument(Manager &mgr, return {nullptr}; } // Add its text. - Variant text{std::map{ - {"content", Variant("Some introductory text")}}}; - Rooted foreword_text = - DocumentPrimitive::buildEntity(foreword, text, "text"); + Rooted foreword_text = + StructuredEntity::buildEntity(foreword, {bookDomain}, "text"); if (foreword_text.isNull()) { return {nullptr}; } + // And its primitive content + Variant text{"Some introductory text"}; + Rooted foreword_primitive = + DocumentPrimitive::buildEntity(foreword_text, text, "content"); + if (foreword_primitive.isNull()) { + return {nullptr}; + } // Add a section. Rooted section = StructuredEntity::buildEntity(root, {bookDomain}, "section"); @@ -67,13 +72,18 @@ static Rooted constructBookDocument(Manager &mgr, return {nullptr}; } // Add its text. - text = Variant{std::map{ - {"content", Variant("Some introductory text")}}}; - Rooted main_text = - DocumentPrimitive::buildEntity(foreword, text, "text"); + Rooted main_text = + StructuredEntity::buildEntity(main, {bookDomain}, "text"); if (main_text.isNull()) { return {nullptr}; } + // And its primitive content + text = Variant{"Some actual text"}; + Rooted main_primitive = + DocumentPrimitive::buildEntity(main_text, text, "content"); + if (main_primitive.isNull()) { + return {nullptr}; + } return doc; } diff --git a/test/core/model/TestDomain.hpp b/test/core/model/TestDomain.hpp index d55bff7..f457531 100644 --- a/test/core/model/TestDomain.hpp +++ b/test/core/model/TestDomain.hpp @@ -81,11 +81,20 @@ static Rooted constructBookDomain(Manager &mgr, Logger &logger) section_field->getChildren().push_back(paragraph); book_field->getChildren().push_back(paragraph); domain->getStructureClasses().push_back(paragraph); + // And the field of it. + Rooted paragraph_field{new FieldDescriptor(mgr, paragraph)}; + paragraph->getFieldDescriptors().push_back(paragraph_field); + + // Finally we add the "text" node, which is transparent as well. + Rooted text{new StructuredClass( + mgr, "text", domain, any, {nullptr}, {nullptr}, true)}; + paragraph_field->getChildren().push_back(text); + domain->getStructureClasses().push_back(text); // ... and has a primitive field. - Rooted paragraph_field{new FieldDescriptor( - mgr, paragraph, domain->getTypesystems()[0]->getTypes()[1], "text", + Rooted text_field{new FieldDescriptor( + mgr, text, domain->getTypesystems()[0]->getTypes()[0], "content", false)}; - paragraph->getFieldDescriptors().push_back(paragraph_field); + text->getFieldDescriptors().push_back(text_field); return domain; } -- cgit v1.2.3 From 319ad738f677a20403cc27192f1df7bb65ce8c0e Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Sun, 4 Jan 2015 19:40:21 +0100 Subject: corrected first draft of DemoOutput. Still some TODOs remain, but for the easy test document everything works. --- CMakeLists.txt | 13 +++++++++- src/plugins/html/DemoOutput.cpp | 26 +++++++++---------- test/plugins/html/DemoOutputTest.cpp | 49 ++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 test/plugins/html/DemoOutputTest.cpp (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index ddb087e..10e43ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,6 +241,16 @@ IF(TEST) ousia_css ) + ADD_EXECUTABLE(ousia_test_html + test/plugins/html/DemoOutputTest + ) + + TARGET_LINK_LIBRARIES(ousia_test_html + ${GTEST_LIBRARIES} + ousia_core + ousia_html + ) + ADD_EXECUTABLE(ousia_test_xml test/plugins/xml/XmlParserTest ) @@ -264,8 +274,9 @@ IF(TEST) # Register the unit tests ADD_TEST(ousia_test_core ousia_test_core) ADD_TEST(ousia_test_boost ousia_test_boost) - ADD_TEST(ousia_test_xml ousia_test_xml) ADD_TEST(ousia_test_css ousia_test_css) + ADD_TEST(ousia_test_html ousia_test_html) + ADD_TEST(ousia_test_xml ousia_test_xml) # ADD_TEST(ousia_test_mozjs ousia_test_mozjs) ENDIF() diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp index 6b9b3a4..463a5d2 100644 --- a/src/plugins/html/DemoOutput.cpp +++ b/src/plugins/html/DemoOutput.cpp @@ -31,7 +31,7 @@ void DemoHTMLTransformer::writeHTML(Handle doc, out << "\n"; out << "\n"; out << "\t\n"; - out << "\t\tTest HTML Output for" << doc->getName() << "\n"; + out << "\t\tTest HTML Output for " << doc->getName() << "\n"; out << "\t\n"; out << "\t\n"; @@ -76,10 +76,9 @@ void DemoHTMLTransformer::writeSection(Handle sec, // if the input node is no section, we ignore it. return; } - // get the fields. - std::vector> &fields = sec->getFields(); // check if we have a heading. - if (fields.size() > 1 && fields[1].size() > 0) { + if (sec->hasField("heading")) { + Rooted heading = sec->getField("heading")[0]; out << "\t\t"; switch (type) { case SectionType::BOOK: @@ -99,7 +98,7 @@ void DemoHTMLTransformer::writeSection(Handle sec, break; } // the second field marks the heading. So let's write it. - writeParagraph(fields[1][0], out, false); + writeParagraph(heading, out, false); // close the heading tag. switch (type) { case SectionType::BOOK: @@ -122,7 +121,8 @@ void DemoHTMLTransformer::writeSection(Handle sec, } // then write the section content recursively. - for (auto &n : fields[0]) { + NodeVector mainField = sec->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 @@ -149,15 +149,13 @@ void DemoHTMLTransformer::writeParagraph(Handle par, if (par->getDescriptor()->getName() != "paragraph") { throw OusiaException("Expected paragraph!"); } - // get the fields. - std::vector> &fields = par->getFields(); - // write heading if its there. // check if we have a heading. - if (fields.size() > 1 && fields[1].size() > 0) { + if (par->hasField("heading")) { + Rooted heading = par->getField("heading")[0]; // start the heading tag out << "\t\t
"; // the second field marks the heading. So let's write it. - writeParagraph(fields[1][0], out, false); + writeParagraph(heading, out, false); // close the heading tag. out << "
\n"; } @@ -167,13 +165,13 @@ void DemoHTMLTransformer::writeParagraph(Handle par, } // write content // TODO: What about emphasis? - for (auto &text : fields[0]) { + for (auto &text : par->getField()) { if (text->getDescriptor()->getName() != "text") { throw OusiaException("Expected text!"); } Handle primitive = - text->getFields()[0][0].cast(); - if (primitive == nullptr) { + text->getField()[0].cast(); + if (primitive.isNull()) { throw OusiaException("Text field is not primitive!"); } out << primitive->getContent().asString(); diff --git a/test/plugins/html/DemoOutputTest.cpp b/test/plugins/html/DemoOutputTest.cpp new file mode 100644 index 0000000..b81a001 --- /dev/null +++ b/test/plugins/html/DemoOutputTest.cpp @@ -0,0 +1,49 @@ +/* + 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 . +*/ + +#include + +#include + +#include + +#include +#include + +#include +#include + +namespace ousia { +namespace html { + +TEST(DemoHTMLTransformer, writeHTML) +{ + // Construct Manager + Logger logger; + Manager mgr{1}; + // Get the domain. + Rooted domain = model::constructBookDomain(mgr, logger); + // Construct the document. + Rooted doc = model::constructBookDocument(mgr, domain); + + // print it + DemoHTMLTransformer transformer; + transformer.writeHTML(doc, std::cout); +} +} +} -- cgit v1.2.3