From 2c3b327739b79d5ba7fe931e205bec1ad320b360 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Thu, 8 Jan 2015 18:11:21 +0100 Subject: further extended the advanced document example, slightly improved XML serialization and fixed a bug in DemoOutput leading to errors if a section/paragraph had no heading. --- src/plugins/html/DemoOutput.cpp | 50 ++++++++++++++++++++++++++++------------- src/plugins/html/DemoOutput.hpp | 8 +------ 2 files changed, 35 insertions(+), 23 deletions(-) (limited to 'src/plugins/html') diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp index 035ba25..eac240b 100644 --- a/src/plugins/html/DemoOutput.cpp +++ b/src/plugins/html/DemoOutput.cpp @@ -30,10 +30,18 @@ void DemoHTMLTransformer::writeHTML(Handle doc, { Manager &mgr = doc->getManager(); // Create an XML object tree for the document first. - Rooted html{new xml::Element{mgr, "html"}}; + 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); @@ -56,20 +64,21 @@ void DemoHTMLTransformer::writeHTML(Handle doc, body->children.push_back(book); // After the content has been transformed, we serialize it. - html->serialize(out); + html->serialize( + out, + ""); } /** * This is just for easier internal handling. */ -enum class SectionType { BOOK, CHAPTER, SECTION, SUBSECTION, NONE }; +enum class SectionType { BOOK, 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") { @@ -79,7 +88,8 @@ SectionType getSectionType(const std::string &name) } } -Rooted DemoHTMLTransformer::transformSection(Handle section) +Rooted DemoHTMLTransformer::transformSection( + Handle section) { Manager &mgr = section->getManager(); // check the section type. @@ -93,7 +103,8 @@ Rooted DemoHTMLTransformer::transformSection(Handle sec{ new xml::Element{mgr, "div", {{"class", secclass}}}}; // check if we have a heading. - if (section->hasField("heading")) { + if (section->hasField("heading") && + section->getField("heading").size() > 0) { Rooted heading = section->getField("heading")[0]; std::string headingclass; @@ -101,14 +112,11 @@ Rooted DemoHTMLTransformer::transformSection(Handle DemoHTMLTransformer::transformSection(Handle DemoHTMLTransformer::transformParagraph(Handle par) +Rooted DemoHTMLTransformer::transformParagraph( + Handle par) { Manager &mgr = par->getManager(); - // create the p xml::Element + // create the p Element Rooted p{new xml::Element{mgr, "p"}}; // check if we have a heading. - if (par->hasField("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"}}; @@ -172,7 +181,7 @@ Rooted DemoHTMLTransformer::transformParagraph(Handlechildren.push_back(n); } } - + // transform paragraph children to XML as well for (auto &n : par->getField()) { std::string childDescriptorName = n->getDescriptor()->getName(); @@ -189,5 +198,14 @@ Rooted DemoHTMLTransformer::transformParagraph(Handle +// 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 +//} } } diff --git a/src/plugins/html/DemoOutput.hpp b/src/plugins/html/DemoOutput.hpp index 70a5daa..0819d7f 100644 --- a/src/plugins/html/DemoOutput.hpp +++ b/src/plugins/html/DemoOutput.hpp @@ -46,13 +46,7 @@ private: */ Rooted transformSection(Handle sec); Rooted transformParagraph(Handle par); - /** - * This method is to be called recursively to write a list to HTML. - * TODO: Implement - */ -// void writeList(Handle sec, std::ostream& out, -// int tabdepth); - +// Rooted transformList(Handle list); //TODO: Implement emphasis. public: -- cgit v1.2.3 From b05499223916879e051d102e1b7e2fd080f46e7d Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Thu, 8 Jan 2015 20:31:30 +0100 Subject: further extended advanced document (now list domain is supported as well) and extended DemoOutput accordingly. --- src/core/model/Domain.cpp | 20 ++++---- src/core/model/Domain.hpp | 6 --- src/plugins/html/DemoOutput.cpp | 38 ++++++++++----- src/plugins/html/DemoOutput.hpp | 4 +- test/core/model/TestAdvanced.hpp | 92 ++++++++++++++++++++++++++++++++++-- test/plugins/html/DemoOutputTest.cpp | 5 +- 6 files changed, 132 insertions(+), 33 deletions(-) (limited to 'src/plugins/html') diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp index f9e2a55..49a3200 100644 --- a/src/core/model/Domain.cpp +++ b/src/core/model/Domain.cpp @@ -53,16 +53,16 @@ void Descriptor::doResolve(std::vector> &res, // &DESCRIPTOR_ATTRIBUTES_ALIAS); } -void StructuredClass::doResolve(std::vector> &res, - const std::vector &path, - Filter filter, void *filterData, unsigned idx, - VisitorSet &visited) -{ - Descriptor::doResolve(res, path, filter, filterData, idx, visited); - if (!isa.isNull()) { - isa->doResolve(res, path, filter, filterData, idx, visited); - } -} +//void StructuredClass::doResolve(std::vector> &res, +// const std::vector &path, +// Filter filter, void *filterData, unsigned idx, +// VisitorSet &visited) +//{ +// Descriptor::doResolve(res, path, filter, filterData, idx, visited); +// if (!isa.isNull()) { +// isa->doResolve(res, path, filter, filterData, idx, visited); +// } +//} void Domain::doResolve(std::vector> &res, const std::vector &path, Filter filter, diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index 8d5de0c..6a07b32 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -468,12 +468,6 @@ private: Owned isa; NodeVector parents; -protected: - void doResolve(std::vector> &res, - const std::vector &path, Filter filter, - void *filterData, unsigned idx, - VisitorSet &visited) override; - public: const bool transparent; // TODO: Is it possible to have root=true and cardinality other than 1? diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp index eac240b..307d37a 100644 --- a/src/plugins/html/DemoOutput.cpp +++ b/src/plugins/html/DemoOutput.cpp @@ -147,9 +147,8 @@ Rooted DemoHTMLTransformer::transformSection( Rooted child; if (childDescriptorName == "paragraph") { child = transformParagraph(n); - // TODO: Implement - // } else if(childDescriptorName == "ul"){ - // writeList(n, out); + } else if (childDescriptorName == "ul" || childDescriptorName == "ol") { + child = transformList(n); } else { child = transformSection(n); } @@ -199,13 +198,30 @@ Rooted DemoHTMLTransformer::transformParagraph( 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 -//} +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; +} } } diff --git a/src/plugins/html/DemoOutput.hpp b/src/plugins/html/DemoOutput.hpp index 0819d7f..6c046e7 100644 --- a/src/plugins/html/DemoOutput.hpp +++ b/src/plugins/html/DemoOutput.hpp @@ -46,8 +46,8 @@ private: */ Rooted transformSection(Handle sec); Rooted transformParagraph(Handle par); -// Rooted transformList(Handle list); - //TODO: Implement emphasis. + Rooted transformList(Handle list); +// TODO: Implement emphasis. public: /** diff --git a/test/core/model/TestAdvanced.hpp b/test/core/model/TestAdvanced.hpp index bb7671a..bec00f9 100644 --- a/test/core/model/TestAdvanced.hpp +++ b/test/core/model/TestAdvanced.hpp @@ -56,7 +56,7 @@ static Rooted constructHeadingDomain(Manager &mgr, card.merge({0, 1}); // set up heading StructuredClass. Rooted heading{new StructuredClass( - mgr, "heading", {nullptr}, card, {nullptr}, {nullptr}, true)}; + mgr, "heading", domain, card, {nullptr}, {nullptr}, true)}; // as field we actually want to refer to the field of paragraph. Rooted p = resolveDescriptor(bookDomain, "paragraph"); heading->getFieldDescriptors().push_back(p->getFieldDescriptors()[0]); @@ -75,6 +75,40 @@ static Rooted constructHeadingDomain(Manager &mgr, return domain; } +/** + * This constructs the "list" domain given the book domain. + */ +static Rooted constructListDomain(Manager &mgr, + Handle sys, + Handle bookDomain, + Logger &logger) +{ + // set up domain node. + Rooted domain{new Domain(mgr, sys, "list")}; + // set up cardinality + Cardinality any; + any.merge(Range::typeRangeFrom(0)); + // get book.paragraph + Rooted p = resolveDescriptor(bookDomain, "paragraph"); + // set up item StructuredClass; + Rooted item{new StructuredClass( + mgr, "item", domain, any, {nullptr}, {nullptr}, false)}; + domain->getStructureClasses().push_back(item); + // as field we actually want to refer to the field of paragraph. + item->getFieldDescriptors().push_back(p->getFieldDescriptors()[0]); + // set up list StructuredClasses. + std::vector listTypes{"ol", "ul"}; + for (auto &listType : listTypes) { + Rooted list{new StructuredClass( + mgr, listType, domain, any, {nullptr}, p, false)}; + Rooted list_field{new FieldDescriptor(mgr, list)}; + list_field->getChildren().push_back(item); + list->getFieldDescriptors().push_back(list_field); + domain->getStructureClasses().push_back(list); + } + return domain; +} + static bool addText(Handle parent, std::vector> &doms, const std::string &content) @@ -120,9 +154,10 @@ static bool addHeading(Handle parent, */ static Rooted constructAdvancedDocument(Manager &mgr, Rooted bookDom, - Rooted headingDom) + Rooted headingDom, + Rooted listDom) { - std::vector> doms{bookDom, headingDom}; + std::vector> doms{bookDom, headingDom, listDom}; // Start with the (empty) document. Rooted doc{new Document(mgr, "kant_was_ist_aufklaerung.oxd")}; @@ -144,6 +179,9 @@ static Rooted constructAdvancedDocument(Manager &mgr, // Add the main section. Rooted sec = StructuredEntity::buildEntity(book, doms, "section"); + if (sec.isNull()) { + return {nullptr}; + } // Add the heading. if (!addHeading(sec, doms, "Was ist Aufklärung?")) { @@ -154,6 +192,9 @@ static Rooted constructAdvancedDocument(Manager &mgr, { Rooted p = StructuredEntity::buildEntity(sec, doms, "paragraph"); + if (p.isNull()) { + return {nullptr}; + } // Add its text. // TODO: Use em and strong here if (!addText(p, doms, @@ -172,6 +213,51 @@ static Rooted constructAdvancedDocument(Manager &mgr, } } + // Add the "Lesarten" section + Rooted lesarten = + StructuredEntity::buildEntity(book, doms, "section"); + if (lesarten.isNull()) { + return {nullptr}; + } + // Add the heading. + if (!addHeading(lesarten, doms, "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 ul = + StructuredEntity::buildEntity(lesarten, {listDom}, "ul"); + if (ul.isNull()) { + return {nullptr}; + } + std::vector citations{ + "Berlinische Monatsschrift. Dezember-Heft 1784. S. 481–494.", + "Kant. Kleine Schriften. Neuwied 1793. Haupt. 8o. S. 34–50.", + "I. Kant. Zerstreute Aufsätze. Frankfurt und Leipzig 1793. 8o. S. " + "25–37.", + "I. Kant. Sämmtliche kleine Schriften. 4 Bände. 1797–98. 8o. " + "Königsberg u. Leipzig (Voigt, Jena). Nachdruck. Bd. III, S. " + "159–172.", + " I. Kant's vermischte Schriften. 3 Bände. Halle 1799. " + "(Tieftrunk). Bd. II. S. 687–700.", + "Kant. Vorzügliche kleine Schriften und Aufsätze, hrsg. mit Noten " + "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 item = + StructuredEntity::buildEntity(ul, {listDom}, "item"); + if (item.isNull()) { + return {nullptr}; + } + if (!addText(item, doms, cit)) { + return {nullptr}; + } + } + } + return doc; } } diff --git a/test/plugins/html/DemoOutputTest.cpp b/test/plugins/html/DemoOutputTest.cpp index 7857314..471ccc3 100644 --- a/test/plugins/html/DemoOutputTest.cpp +++ b/test/plugins/html/DemoOutputTest.cpp @@ -43,8 +43,11 @@ TEST(DemoHTMLTransformer, writeHTML) model::constructBookDomain(mgr, sys, logger); Rooted headingDom = model::constructHeadingDomain(mgr, sys, bookDom, logger); + Rooted listDom = + model::constructListDomain(mgr, sys, bookDom, logger); // Construct the document. - Rooted doc = model::constructAdvancedDocument(mgr, bookDom, headingDom); + Rooted doc = + model::constructAdvancedDocument(mgr, bookDom, headingDom, listDom); #ifdef MANAGER_GRAPHVIZ_EXPORT // dump the manager state -- cgit v1.2.3 From 235cf24518ca40bec59b497a416d9831db12eaa3 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Thu, 8 Jan 2015 21:30:31 +0100 Subject: further extended example to include annotations (emphasized and strong). The DemoOutput for that is still missing, though. convenience build functions have also been implemented in Document.cpp. --- src/core/model/Document.cpp | 54 +++++++++++++++- src/core/model/Document.hpp | 58 +++++++++++++---- src/core/model/Domain.hpp | 10 ++- src/plugins/html/DemoOutput.cpp | 5 +- test/core/model/TestAdvanced.hpp | 117 +++++++++++++++++++++++++++++------ test/plugins/html/DemoOutputTest.cpp | 2 + 6 files changed, 211 insertions(+), 35 deletions(-) (limited to 'src/plugins/html') diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 073f728..c653fe3 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -100,7 +100,7 @@ static Rooted resolveDescriptor( } // Otherwise take the first valid result. for (auto &r : resolved) { - if(r->isa(typeOf())){ + if (r->isa(typeOf())) { return r.cast(); } } @@ -155,6 +155,9 @@ Rooted StructuredEntity::buildEntity( return {nullptr}; } // append the new entity to the right field. + if (!parent->hasField(fieldName)) { + return {nullptr}; + } NodeVector &field = parent->getField(fieldName); field.push_back(entity); @@ -178,13 +181,60 @@ Rooted DocumentPrimitive::buildEntity( return {nullptr}; } // append the new entity to the right field. + if (!parent->hasField(fieldName)) { + return {nullptr}; + } NodeVector &field = parent->getField(fieldName); field.push_back(entity); - // and return it. return entity; } +Rooted AnnotationEntity::buildAnchor( + Handle 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{ + new AnnotationEntity::Anchor(parent->getManager(), parent, id)}; + // append the new entity to the right field. + if (!parent->hasField(fieldName)) { + return {nullptr}; + } + NodeVector &field = parent->getField(fieldName); + field.push_back(anchor); + // and return it. + return anchor; +} + +Rooted AnnotationEntity::buildEntity( + Handle parent, std::vector> domains, + const std::string &className, Handle start, + Handle 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 = resolveDescriptor(domains, className); + if (descriptor == nullptr) { + return {nullptr}; + } + // Then construct the AnnotationEntity itself + Rooted anno{ + new AnnotationEntity(parent->getManager(), parent, descriptor, + attributes, start, end, name)}; + // append the new entity to the document + parent->getAnnotations().push_back(anno); + // and return it. + return anno; +} + /* Type registrations */ } diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index 7523962..993df9e 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -207,21 +207,15 @@ public: * information please refer to the header documentation above. */ class StructuredEntity : public DocumentEntity { -private: - NodeVector annotations; - public: StructuredEntity(Manager &mgr, Handle parent, Handle descriptor, Variant attributes, std::string name = "") : DocumentEntity(mgr, parent, descriptor, std::move(attributes), - std::move(name)), - annotations(this) + std::move(name)) { } - NodeVector &getAnnotations() { return annotations; } - /** * This builds the root StructuredEntity for the given document. It * automatically appends the newly build entity to the given document. @@ -343,12 +337,11 @@ public: public: /** * @param mgr is the Manager instance. - * @param name is the Anchor id. * @param parent is the parent of this Anchor in the Structure Tree (!), * not the AnnotationEntity that references this Anchor. + * @param name is the Anchor id. */ - Anchor(Manager &mgr, Handle parent, - std::string name = "") + Anchor(Manager &mgr, Handle parent, std::string name) : StructuredEntity(mgr, parent, nullptr, Variant(), std::move(name)) { } @@ -372,6 +365,45 @@ public: Rooted getStart() { return start; } Rooted 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 buildAnchor(Handle 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 buildEntity(Handle parent, std::vector> domains, + const std::string &className, + Handle start, Handle end, + Variant attributes = Variant(), std::string name = ""); }; /** @@ -382,17 +414,21 @@ class Document : public Node { private: // TODO: Might there be several roots? E.g. metadata? Owned root; + NodeVector annotations; public: Document(Manager &mgr, std::string name) // TODO: Can a document have a parent? - : Node(mgr, std::move(name), nullptr) + : Node(mgr, std::move(name), nullptr), + annotations(this) { } void setRoot(Handle root) { this->root = acquire(root); }; Rooted getRoot() const { return root; } + + NodeVector getAnnotations() { return annotations; } }; } diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index 6a07b32..027cf88 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -306,8 +306,7 @@ public: */ FieldDescriptor(Manager &mgr, Handle parent, FieldType fieldType = FieldType::TREE, - std::string name = "", - bool optional = false) + std::string name = "", bool optional = false) : Node(mgr, std::move(name), parent), children(this), fieldType(fieldType), @@ -532,6 +531,13 @@ public: * This class has no special properties and is in essence just a Descriptor. */ class AnnotationClass : public Descriptor { +public: + AnnotationClass(Manager &mgr, std::string name, Handle domain, + // TODO: What would be a wise default value for attributes? + Handle attributesDescriptor) + : Descriptor(mgr, std::move(name), domain, attributesDescriptor) + { + } }; /** diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp index 307d37a..c858695 100644 --- a/src/plugins/html/DemoOutput.cpp +++ b/src/plugins/html/DemoOutput.cpp @@ -183,6 +183,10 @@ Rooted DemoHTMLTransformer::transformParagraph( // transform paragraph children to XML as well for (auto &n : par->getField()) { + if (n->isa(typeOf())) { + // TODO: Handle Anchors! + continue; + } std::string childDescriptorName = n->getDescriptor()->getName(); if (childDescriptorName == "text") { Handle primitive = @@ -193,7 +197,6 @@ Rooted DemoHTMLTransformer::transformParagraph( p->children.push_back( new xml::Text(mgr, primitive->getContent().asString())); } - // TODO: Handle non-text content } return p; } diff --git a/test/core/model/TestAdvanced.hpp b/test/core/model/TestAdvanced.hpp index bec00f9..5af6003 100644 --- a/test/core/model/TestAdvanced.hpp +++ b/test/core/model/TestAdvanced.hpp @@ -109,6 +109,25 @@ static Rooted constructListDomain(Manager &mgr, return domain; } +/** + * This constructs the "emphasis" domain. + */ +static Rooted constructEmphasisDomain(Manager &mgr, + Handle sys, + Logger &logger) +{ + // set up domain node. + Rooted domain{new Domain(mgr, sys, "emphasis")}; + // create AnnotationClasses + Rooted em{ + new AnnotationClass(mgr, "emphasized", domain, {nullptr})}; + domain->getAnnotationClasses().push_back(em); + Rooted strong{ + new AnnotationClass(mgr, "strong", domain, {nullptr})}; + domain->getAnnotationClasses().push_back(strong); + return domain; +} + static bool addText(Handle parent, std::vector> &doms, const std::string &content) @@ -147,6 +166,34 @@ static bool addHeading(Handle parent, return true; } +static int annoIdx = 1; + +// Only works for non-overlapping annotations! +static bool addAnnotation(Handle doc, Handle parent, + std::vector> &doms, + const std::string &text, const std::string &annoClass) +{ + Rooted start = + AnnotationEntity::buildAnchor(parent, std::to_string(annoIdx++)); + if (start.isNull()) { + return false; + } + if (!addText(parent, doms, text)) { + return false; + } + Rooted end = + AnnotationEntity::buildAnchor(parent, std::to_string(annoIdx++)); + if (end.isNull()) { + return false; + } + Rooted anno = + AnnotationEntity::buildEntity(doc, doms, annoClass, start, end); + if (anno.isNull()) { + return false; + } + return true; +} + /** * This constructs a more advanced book document using not only the book * domain but also headings, emphasis and lists. @@ -170,10 +217,19 @@ static Rooted constructAdvancedDocument(Manager &mgr, } // Add the heading. - // TODO: use em here. - if (!addHeading(book, doms, - "Beantwortung der Frage: Was ist Aufklärung?")) { - return {nullptr}; + { + Rooted heading = StructuredEntity::buildEntity( + book, doms, "heading", "heading", {}, ""); + if (heading.isNull()) { + return {nullptr}; + } + if (!addText(heading, doms, "Beantwortung der Frage: ")) { + return {nullptr}; + } + if (!addAnnotation(doc, heading, doms, "Was ist Aufklärung?", + "emphasized")) { + return {nullptr}; + } } // Add the main section. @@ -196,20 +252,43 @@ static Rooted constructAdvancedDocument(Manager &mgr, return {nullptr}; } // Add its text. - // TODO: Use em and strong here - if (!addText(p, doms, - " Aufklärung ist der Ausgang des Menschen aus " - "seiner selbstverschuldeten Unmündigkeit. " - "Unmündigkeit ist das Unvermögen, sich seines " - "Verstandes ohne Leitung eines anderen zu bedienen. " - "Selbstverschuldet 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. Sapere " - "aude! Habe Mut, dich deines eigenen Verstandes zu " - "bedienen! ist also der Wahlspruch der " - "Aufklärung.")) { - return {nullptr}; + { + if (!addAnnotation(doc, p, doms, + "Aufklärung ist der Ausgang des Menschen aus " + "seiner selbstverschuldeten Unmündigkeit", + "strong")) { + return {nullptr}; + } + if (!addAnnotation(doc, p, doms, "Unmündigkeit", + "emphasized")) { + return {nullptr}; + } + if (!addText(p, doms, + "ist das Unvermögen, sich seines Verstandes ohne " + "Leitung eines anderen zu bedienen. ")) { + return {nullptr}; + } + if (!addAnnotation(doc, p, doms, "Selbstverschuldet", + "emphasized")) { + return {nullptr}; + } + if (!addText(p, doms, + " 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, + "Sapere aude! Habe Mut, dich deines eigenen " + "Verstandes zu bedienen!", + "emphasized")) { + return {nullptr}; + } + if (!addText(p, doms, + " ist also der Wahlspruch der Aufklärung.")) { + return {nullptr}; + } } } @@ -225,7 +304,7 @@ static Rooted constructAdvancedDocument(Manager &mgr, } // Add list with citations { - //TODO: We need to restrict this to the list domain. Otherwise + // TODO: We need to restrict this to the list domain. Otherwise // this leads to resolve errors for some reason. Rooted ul = StructuredEntity::buildEntity(lesarten, {listDom}, "ul"); diff --git a/test/plugins/html/DemoOutputTest.cpp b/test/plugins/html/DemoOutputTest.cpp index 471ccc3..36b53b4 100644 --- a/test/plugins/html/DemoOutputTest.cpp +++ b/test/plugins/html/DemoOutputTest.cpp @@ -45,6 +45,8 @@ TEST(DemoHTMLTransformer, writeHTML) model::constructHeadingDomain(mgr, sys, bookDom, logger); Rooted listDom = model::constructListDomain(mgr, sys, bookDom, logger); + Rooted emDom = + model::constructEmphasisDomain(mgr, sys, logger); // Construct the document. Rooted doc = model::constructAdvancedDocument(mgr, bookDom, headingDom, listDom); -- cgit v1.2.3 From 4ec16559eba87553241e2e20a9e31a62b7aed08a Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Thu, 8 Jan 2015 23:33:24 +0100 Subject: first attempts on implementing annotation support for DemoHTML output. --- src/plugins/html/DemoOutput.cpp | 116 +++++++++++++++++++++++++++------------- src/plugins/html/DemoOutput.hpp | 30 ++++++++--- 2 files changed, 103 insertions(+), 43 deletions(-) (limited to 'src/plugins/html') diff --git a/src/plugins/html/DemoOutput.cpp b/src/plugins/html/DemoOutput.cpp index c858695..92ff88c 100644 --- a/src/plugins/html/DemoOutput.cpp +++ b/src/plugins/html/DemoOutput.cpp @@ -16,6 +16,9 @@ along with this program. If not, see . */ +#include + + #include #include #include @@ -53,13 +56,23 @@ void DemoHTMLTransformer::writeHTML(Handle doc, // So far was the "preamble". No we have to get to the document content. + // build the start and end map for annotation processing. + AnnoMap startMap; + AnnoMap endMap; + for (auto &a : doc->getAnnotations()) { + // we assume uniquely IDed annotations, which should be checked in the + // validation process. + startMap.emplace(a->getStart()->getName(), a); + endMap.emplace(a->getEnd()->getName(), a); + } + // 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); + Rooted book = transformSection(root, startMap, endMap); // add it as child to the body node. body->children.push_back(book); @@ -89,7 +102,7 @@ SectionType getSectionType(const std::string &name) } Rooted DemoHTMLTransformer::transformSection( - Handle section) + Handle section, AnnoMap &startMap, AnnoMap &endMap) { Manager &mgr = section->getManager(); // check the section type. @@ -125,7 +138,8 @@ Rooted DemoHTMLTransformer::transformSection( 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); + Rooted h_content = + transformParagraph(heading, startMap, endMap); // We omit the paragraph Element and add the children directly to the // heading Element for (auto &n : h_content->children) { @@ -146,11 +160,11 @@ Rooted DemoHTMLTransformer::transformSection( const std::string childDescriptorName = n->getDescriptor()->getName(); Rooted child; if (childDescriptorName == "paragraph") { - child = transformParagraph(n); + child = transformParagraph(n, startMap, endMap); } else if (childDescriptorName == "ul" || childDescriptorName == "ol") { - child = transformList(n); + child = transformList(n, startMap, endMap); } else { - child = transformSection(n); + child = transformSection(n, startMap, endMap); } if (!child.isNull()) { sec->children.push_back(child); @@ -159,8 +173,38 @@ Rooted DemoHTMLTransformer::transformSection( return sec; } +Rooted DemoHTMLTransformer::transformList( + Handle list, AnnoMap &startMap, AnnoMap &endMap) +{ + 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, 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); + } + } + } + return l; +} + +typedef model::AnnotationEntity::Anchor Anchor; +typedef std::stack> AnnoStack; + Rooted DemoHTMLTransformer::transformParagraph( - Handle par) + Handle par, AnnoMap &startMap, AnnoMap &endMap) { Manager &mgr = par->getManager(); // create the p Element @@ -173,7 +217,8 @@ Rooted DemoHTMLTransformer::transformParagraph( 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); + Rooted h_content = + transformParagraph(heading, startMap, endMap); // We omit the paragraph Element and add the children directly to the // heading Element for (auto &n : h_content->children) { @@ -183,8 +228,33 @@ Rooted DemoHTMLTransformer::transformParagraph( // transform paragraph children to XML as well for (auto &n : par->getField()) { - if (n->isa(typeOf())) { - // TODO: Handle Anchors! + if (n->isa(typeOf())) { + //TODO: This needs some more brain work. +// // check if this is a start Anchor. +// auto it = startMap.find(n->getName()); +// if(it != startMap.end()){ +// // if we have a start Anchor, we put another AnnotationEntity +// // on top the stack. +// opened.push(it->second); +// // and we create an open tag. +// +// continue; +// } +// // check if this is an end Anchor. +// auto it = endMap.find(n->getName()); +// if(it != endMap.end()){ +// /* +// * Now it gets somewhat interesting: We have to close all +// * tags that started after the one that is closed now and +// * re-open them afterwards. So we create a lokal stack to +// * temporarily store all AnnotationEntities that need to +// * be re-opened. +// */ +// AnnoStack tmp; +// Rooted< +// while(!opened.empty() && ) +// } +// continue; } std::string childDescriptorName = n->getDescriptor()->getName(); @@ -200,31 +270,5 @@ Rooted DemoHTMLTransformer::transformParagraph( } 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; -} } } diff --git a/src/plugins/html/DemoOutput.hpp b/src/plugins/html/DemoOutput.hpp index 6c046e7..e08ec2b 100644 --- a/src/plugins/html/DemoOutput.hpp +++ b/src/plugins/html/DemoOutput.hpp @@ -30,6 +30,7 @@ #ifndef _OUSIA_HTML_DEMO_OUTPUT_HPP_ #define _OUSIA_HTML_DEMO_OUTPUT_HPP_ +#include #include #include @@ -38,16 +39,31 @@ namespace ousia { namespace html { +typedef std::map> AnnoMap; + class DemoHTMLTransformer { private: /** - * These methods are called recursively to transform a document to an XML - * tree. + * This transforms a section-like entity, namely book, section + * and subsection, to an XHTML element, including its header. For the + * children of the default field the respective transform function is + * called recursively. + */ + Rooted transformSection(Handle sec, + AnnoMap& startMap, AnnoMap& endMap); + /** + * This transforms a list entity, namely ul and ol to an XHTML element. + * For each item, the transformParagraph function is called. + */ + Rooted transformList(Handle list, + AnnoMap& startMap, AnnoMap& endMap); + /** + * This transforms a paragraph-like entity, namely heading, item and + * paragraph, to an XHTML element including the text and the anchors + * contained. For anchor handling we require the AnnoMaps. */ - Rooted transformSection(Handle sec); - Rooted transformParagraph(Handle par); - Rooted transformList(Handle list); -// TODO: Implement emphasis. + Rooted transformParagraph(Handle par, + AnnoMap& startMap, AnnoMap& endMap); public: /** @@ -68,7 +84,7 @@ public: * 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); + void writeHTML(Handle doc, std::ostream &out); }; } } -- cgit v1.2.3