From a7019614896fdd3e29b9a28f6a8cfd2c1b365983 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Sun, 1 Mar 2015 20:47:25 +0100 Subject: Renamed domain to ontology. --- src/core/model/Document.cpp | 8 +- src/core/model/Document.hpp | 58 +- src/core/model/Domain.cpp | 981 ------------------- src/core/model/Domain.hpp | 1203 ------------------------ src/core/model/Node.hpp | 4 +- src/core/model/Ontology.cpp | 981 +++++++++++++++++++ src/core/model/Ontology.hpp | 1203 ++++++++++++++++++++++++ src/core/model/Project.cpp | 6 +- src/core/model/Project.hpp | 14 +- src/core/model/RootNode.hpp | 2 +- src/core/parser/ParserScope.cpp | 2 +- src/core/parser/stack/DocumentHandler.cpp | 2 +- src/core/parser/stack/DocumentHandler.hpp | 2 +- src/core/parser/stack/DomainHandler.cpp | 417 -------- src/core/parser/stack/DomainHandler.hpp | 257 ----- src/core/parser/stack/GenericParserStates.cpp | 26 +- src/core/parser/stack/ImportIncludeHandler.cpp | 6 +- src/core/parser/stack/OntologyHandler.cpp | 417 ++++++++ src/core/parser/stack/OntologyHandler.hpp | 257 +++++ src/core/parser/stack/TypesystemHandler.cpp | 16 +- src/core/resource/Resource.cpp | 2 +- src/core/resource/Resource.hpp | 4 +- src/core/resource/ResourceRequest.cpp | 4 +- 23 files changed, 2936 insertions(+), 2936 deletions(-) delete mode 100644 src/core/model/Domain.cpp delete mode 100644 src/core/model/Domain.hpp create mode 100644 src/core/model/Ontology.cpp create mode 100644 src/core/model/Ontology.hpp delete mode 100644 src/core/parser/stack/DomainHandler.cpp delete mode 100644 src/core/parser/stack/DomainHandler.hpp create mode 100644 src/core/parser/stack/OntologyHandler.cpp create mode 100644 src/core/parser/stack/OntologyHandler.hpp (limited to 'src/core') diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 2fcd20d..fc39348 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -723,7 +723,7 @@ void Document::doResolve(ResolutionState &state) if (root != nullptr) { continueResolveCompositum(root, state); } - continueResolveReferences(domains, state); + continueResolveReferences(ontologies, state); continueResolveReferences(typesystems, state); } @@ -761,8 +761,8 @@ bool Document::doValidate(Logger &logger) const void Document::doReference(Handle node) { - if (node->isa(&RttiTypes::Domain)) { - referenceDomain(node.cast()); + if (node->isa(&RttiTypes::Ontology)) { + referenceOntology(node.cast()); } if (node->isa(&RttiTypes::Typesystem)) { referenceTypesystem(node.cast()); @@ -771,7 +771,7 @@ void Document::doReference(Handle node) RttiSet Document::doGetReferenceTypes() const { - return RttiSet{&RttiTypes::Domain, &RttiTypes::Typesystem}; + return RttiSet{&RttiTypes::Ontology, &RttiTypes::Typesystem}; } Rooted Document::createRootStructuredEntity( diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index a5e40ce..dc0f73f 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -22,29 +22,29 @@ * This header contains the class hierarchy of actual document classes. A graph * of connected instances of these nodes is a "Document". How the different * DocumentEntity instances may be connected within the graph is subject to the - * specification in the respective Domain(s) (see also the Domain.hpp). + * specification in the respective Ontology(s) (see also the Ontology.hpp). * * A Document, from top to bottom, consists of "Document" instance, * which "owns" the structural root node of the in-document graph. This might - * for example be a "book" node of the "book" domain. That root node in turn has + * for example be a "book" node of the "book" ontology. That root node in turn has * structure nodes as children, which in turn may have children. This * constitutes a Structure Tree. Additionally annotations may be attached to * Structure Nodes, effectively resulting in a Document Graph instead of a * Document Tree (other references may introduce cycles as well). * - * Consider this XML representation of a document using the "book" domain: + * Consider this XML representation of a document using the "book" ontology: * * \code{.xml} * * - * - * + * + * * * * * 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). + * additional ontologies (or in this one). * * Here we might have an introduction to the chapter, including some * overview of the chapters structure. @@ -63,9 +63,9 @@ * \endcode * * As can be seen the StructureEntities inherently follow a tree structure that - * is restricted by the implicit context free grammar of the "book" Domain + * is restricted by the implicit context free grammar of the "book" Ontology * definition (e.g. it is not allowed to have a "book" node inside a "section"; - * refer to te Domain.hpp for more information). + * refer to te Ontology.hpp for more information). * * 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 @@ -114,7 +114,7 @@ #include #include "Node.hpp" -#include "Domain.hpp" +#include "Ontology.hpp" #include "RootNode.hpp" #include "Typesystem.hpp" @@ -131,7 +131,7 @@ class Anchor; /** * A DocumentEntity is the common superclass for StructuredEntities and - * AnnotationEntities. Similarly to DescriptorEntity in the Domain.hpp it + * AnnotationEntities. Similarly to DescriptorEntity in the Ontology.hpp it * defines that each node in the Document graph may have attributes (in form * of a struct Variant), and fields. * The fields here are a vector of vectors. The first vector implements all @@ -215,7 +215,7 @@ public: * If the name is unknown an exception is thrown. * * @param fieldName is the name of a field as specified in the - * FieldDescriptor in the Domain description. + * FieldDescriptor in the Ontology description. * @return a NodeVector of all StructuredEntities in that field. */ const NodeVector &getField( @@ -243,7 +243,7 @@ public: * If the index is out of bounds an exception is thrown. * * @param idx is the index of a field as specified in the - * FieldDescriptor in the Domain description. + * FieldDescriptor in the Ontology description. * @return a NodeVector of all StructuredEntities in that field. */ const NodeVector &getField(const size_t &idx) const; @@ -257,7 +257,7 @@ public: * * @param s is the StructureNode that shall be added. * @param fieldIdx is the index of a field as specified in the - * FieldDescriptor in the Domain description. + * FieldDescriptor in the Ontology description. */ void addStructureNode(Handle s, const size_t &fieldIdx); /** @@ -271,7 +271,7 @@ public: * * @param s is the StructureNode that shall be added. * @param fieldName is the name of a field as specified in the - * FieldDescriptor in the Domain description. + * FieldDescriptor in the Ontology description. */ void addStructureNode(Handle s, const std::string &fieldName = DEFAULT_FIELD_NAME); @@ -287,7 +287,7 @@ public: * * @param ss are the StructureNodes that shall be added. * @param fieldName is the name of a field as specified in the - * FieldDescriptor in the Domain description. + * FieldDescriptor in the Ontology description. */ void addStructureNodes(const std::vector> &ss, const std::string &fieldName = DEFAULT_FIELD_NAME); @@ -298,7 +298,7 @@ public: * * @param s is the StructureNode that shall be removed. * @param fieldIdx is the index of a field as specified in the - * FieldDescriptor in the Domain description. + * FieldDescriptor in the Ontology description. * @return true if this StructureNode was a child here and false if * if was not found. */ @@ -313,7 +313,7 @@ public: * * @param s is the StructureNode that shall be removed. * @param fieldName is the name of a field as specified in the - * FieldDescriptor in the Domain description. + * FieldDescriptor in the Ontology description. * @return true if this StructureNode was a child here and false if * if was not found. */ @@ -866,7 +866,7 @@ public: /** * A Document is mainly a wrapper for the Root structure node of the Document - * Graph. It also references the domains that have been used within this + * Graph. It also references the ontologies that have been used within this * document and the AnnotationEntities that span over Anchors in this Document. */ class Document : public RootNode { @@ -874,7 +874,7 @@ private: // TODO: Might there be several roots? E.g. metadata? Owned root; NodeVector annotations; - NodeVector domains; + NodeVector ontologies; NodeVector typesystems; protected: @@ -893,7 +893,7 @@ public: Document(Manager &mgr, std::string name) : RootNode(mgr, std::move(name), nullptr), annotations(this), - domains(this), + ontologies(this), typesystems(this) { } @@ -987,30 +987,30 @@ public: std::string name = ""); /** - * Returns a const reference to the NodeVector of Domains that are used + * Returns a const reference to the NodeVector of ontologies that are used * within this Document. * - * @return a const reference to the NodeVector of Domains that are used + * @return a const reference to the NodeVector of ontologies that are used * within this Document. */ - const NodeVector &getDomains() const { return domains; } + const NodeVector &getOntologys() const { return ontologies; } /** - * Adds a Domain reference to this Document. + * Adds a Ontology reference to this Document. */ - void referenceDomain(Handle d) + void referenceOntology(Handle d) { invalidate(); - domains.push_back(d); + ontologies.push_back(d); } /** - * Adds multiple Domain references to this Document. + * Adds multiple Ontology references to this Document. */ - void referenceDomains(const std::vector> &d) + void referenceOntologys(const std::vector> &d) { invalidate(); - domains.insert(domains.end(), d.begin(), d.end()); + ontologies.insert(ontologies.end(), d.begin(), d.end()); } /** diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp deleted file mode 100644 index 8255401..0000000 --- a/src/core/model/Domain.cpp +++ /dev/null @@ -1,981 +0,0 @@ -/* - 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 "Domain.hpp" - -namespace ousia { - -/* Helper Functions */ - -struct PathState { - std::shared_ptr pred; - Node *node; - size_t length; - - PathState(std::shared_ptr pred, Node *node) - : pred(pred), node(node) - { - if (pred == nullptr) { - length = 1; - } else { - length = pred->length + 1; - } - } -}; - -static void constructPath(std::shared_ptr state, - NodeVector &vec) -{ - if (state->pred != nullptr) { - constructPath(state->pred, vec); - } - vec.push_back(state->node); -} - -static NodeVector pathTo(const Node *start, Logger &logger, - Handle target, bool &success) -{ - success = false; - // shortest path. - NodeVector shortest; - // state queue for breadth-first search. - std::queue> states; - if (start->isa(&RttiTypes::Descriptor)) { - const Descriptor *desc = static_cast(start); - // initially put every field descriptor on the queue. - NodeVector fields = desc->getFieldDescriptors(); - - for (auto fd : fields) { - if (fd == target) { - // if we have found the target directly, return without search. - success = true; - return shortest; - } - if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { - states.push(std::make_shared(nullptr, fd.get())); - } - } - } else { - const FieldDescriptor *field = - static_cast(start); - // initially put every child and its subclasses to the queue. - for (auto c : field->getChildrenWithSubclasses()) { - // if we have found the target directly, return without search. - if (c == target) { - success = true; - return shortest; - } - if (c->isTransparent()) { - states.push(std::make_shared(nullptr, c.get())); - } - } - } - // set of visited nodes. - std::unordered_set visited; - while (!states.empty()) { - std::shared_ptr current = states.front(); - states.pop(); - // do not proceed if this node was already visited. - if (!visited.insert(current->node).second) { - continue; - } - // also do not proceed if we can't get better than the current shortest - // path anymore. - if (!shortest.empty() && current->length > shortest.size()) { - continue; - } - - bool fin = false; - if (current->node->isa(&RttiTypes::StructuredClass)) { - const StructuredClass *strct = - static_cast(current->node); - - // look through all fields. - NodeVector fields = strct->getFieldDescriptors(); - for (auto fd : fields) { - // if we found our target, break off the search in this branch. - if (fd == target) { - fin = true; - continue; - } - // only continue in the TREE field. - if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { - states.push(std::make_shared(current, fd.get())); - } - } - } else { - // otherwise this is a FieldDescriptor. - const FieldDescriptor *field = - static_cast(current->node); - // and we proceed by visiting all permitted children. - for (auto c : field->getChildrenWithSubclasses()) { - // if we found our target, break off the search in this branch. - if (c == target) { - fin = true; - continue; - } - // We only allow to continue our path via transparent children. - if (c->isTransparent()) { - states.push(std::make_shared(current, c.get())); - } - } - } - // check if we are finished. - if (fin) { - success = true; - // if so we look if we found a shorter path than the current minimum - if (shortest.empty() || current->length < shortest.size()) { - NodeVector newPath; - constructPath(current, newPath); - shortest = newPath; - } else if (current->length == shortest.size()) { - // if the length is the same the result is ambigous and we log - // an error. - NodeVector newPath; - constructPath(current, newPath); - logger.error( - std::string("Can not unambigously create a path from \"") + - start->getName() + "\" to \"" + target->getName() + "\"."); - logger.note("Dismissed the path:", SourceLocation{}, - MessageMode::NO_CONTEXT); - for (auto n : newPath) { - logger.note(n->getName()); - } - } - } - } - return shortest; -} - -template -static NodeVector collect(const Node *start, F match) -{ - // result - NodeVector res; - // queue for breadth-first search of graph. - std::queue> q; - // put the initial node on the stack. - q.push(const_cast(start)); - // set of visited nodes. - std::unordered_set visited; - while (!q.empty()) { - Rooted n = q.front(); - q.pop(); - // do not proceed if this node was already visited. - if (!visited.insert(n.get()).second) { - continue; - } - - if (n->isa(&RttiTypes::StructuredClass)) { - Rooted strct = n.cast(); - - // look through all fields. - NodeVector fields = strct->getFieldDescriptors(); - for (auto fd : fields) { - // note matches. - if (match(fd)) { - res.push_back(fd); - } - // only continue in the TREE field. - if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { - q.push(fd); - } - } - } else { - // otherwise this is a FieldDescriptor. - Rooted field = n.cast(); - // and we proceed by visiting all permitted children. - for (auto c : field->getChildrenWithSubclasses()) { - // note matches. - if (match(c)) { - res.push_back(c); - } - // We only continue our search via transparent children. - if (c->isTransparent()) { - q.push(c); - } - } - } - } - return res; -} - -/* Class FieldDescriptor */ - -FieldDescriptor::FieldDescriptor(Manager &mgr, Handle primitiveType, - Handle parent, FieldType fieldType, - std::string name, bool optional) - : Node(mgr, std::move(name), parent), - children(this), - fieldType(fieldType), - primitiveType(acquire(primitiveType)), - optional(optional), - primitive(true) -{ -} - -FieldDescriptor::FieldDescriptor(Manager &mgr, Handle parent, - FieldType fieldType, std::string name, - bool optional) - : Node(mgr, std::move(name), parent), - children(this), - fieldType(fieldType), - optional(optional), - primitive(false) -{ -} - -bool FieldDescriptor::doValidate(Logger &logger) const -{ - bool valid = true; - // check parent type - if (getParent() == nullptr) { - logger.error(std::string("Field \"") + getName() + "\" has no parent!", - *this); - valid = false; - } else if (!getParent()->isa(&RttiTypes::Descriptor)) { - logger.error(std::string("The parent of Field \"") + getName() + - "\" is not a descriptor!", - *this); - valid = false; - } - // check name - if (getName().empty()) { - if (fieldType != FieldType::TREE) { - logger.error(std::string("Field \"") + getName() + - "\" is not the main field but has an empty name!", - *this); - valid = false; - } - } else { - valid = valid & validateName(logger); - } - - // check consistency of FieldType with the rest of the FieldDescriptor. - if (primitive) { - if (children.size() > 0) { - logger.error(std::string("Field \"") + getName() + - "\" is supposed to be primitive but has " - "registered child classes!", - *this); - valid = false; - } - if (primitiveType == nullptr) { - logger.error(std::string("Field \"") + getName() + - "\" is supposed to be primitive but has " - "no primitive type!", - *this); - valid = false; - } - } else { - if (primitiveType != nullptr) { - logger.error(std::string("Field \"") + getName() + - "\" is supposed to be non-primitive but has " - "a primitive type!", - *this); - valid = false; - } - // if this is not a primitive field we require at least one child. - if (children.empty()) { - logger.error(std::string("Field \"") + getName() + - "\" is non primitive but does not allow children!", - *this); - valid = false; - } - } - /* - * we are not allowed to call the validation functions of each child because - * this might lead to cycles. What we should do, however, is to check if - * there are duplicates. - */ - std::set names; - for (Handle c : getChildrenWithSubclasses()) { - if (!names.insert(c->getName()).second) { - logger.error(std::string("Field \"") + getName() + - "\" had multiple children with the name \"" + - c->getName() + "\"", - *this); - valid = false; - } - } - - return valid; -} - -static void gatherSubclasses( - std::unordered_set& visited, - NodeVector &res, Handle strct) -{ - // this check is to prevent cycles. - if (!visited.insert(strct.get()).second) { - return; - } - for (auto sub : strct->getSubclasses()) { - // this check is to prevent cycles. - if(visited.count(sub.get())){ - continue; - } - res.push_back(sub); - gatherSubclasses(visited, res, sub); - } -} - -NodeVector FieldDescriptor::getChildrenWithSubclasses() const -{ - std::unordered_set visited; - NodeVector res; - for (auto c : children) { - res.push_back(c); - gatherSubclasses(visited, res, c); - } - return res; -} - -bool FieldDescriptor::removeChild(Handle c) -{ - auto it = children.find(c); - if (it != children.end()) { - invalidate(); - children.erase(it); - return true; - } - return false; -} - -std::pair, bool> FieldDescriptor::pathTo( - Handle childDescriptor, Logger &logger) const -{ - bool success = false; - NodeVector path = - ousia::pathTo(this, logger, childDescriptor, success); - return std::make_pair(path, success); -} -NodeVector FieldDescriptor::pathTo(Handle field, - Logger &logger) const -{ - bool success = false; - return ousia::pathTo(this, logger, field, success); -} -NodeVector FieldDescriptor::getDefaultFields() const -{ - // TODO: In principle a cast would be nicer here, but for now we copy. - NodeVector nodes = collect(this, [](Handle n) { - if (!n->isa(&RttiTypes::FieldDescriptor)) { - return false; - } - Handle f = n.cast(); - return f->getFieldType() == FieldDescriptor::FieldType::TREE && - f->isPrimitive(); - }); - NodeVector res; - for (auto n : nodes) { - res.push_back(n.cast()); - } - return res; -} - -/* Class Descriptor */ - -void Descriptor::doResolve(ResolutionState &state) -{ - const NodeVector &attributes = - attributesDescriptor->getAttributes(); - continueResolveComposita(attributes, attributes.getIndex(), state); - continueResolveComposita(fieldDescriptors, fieldDescriptors.getIndex(), - state); -} - -bool Descriptor::doValidate(Logger &logger) const -{ - bool valid = true; - // check parent type - if (getParent() == nullptr) { - logger.error( - std::string("Descriptor \"") + getName() + "\" has no parent!", - *this); - valid = false; - } else if (!getParent()->isa(&RttiTypes::Domain)) { - logger.error(std::string("The parent of Descriptor \"") + getName() + - "\" is not a Domain!", - *this); - valid = false; - } - // check name - if (getName().empty()) { - logger.error("The name of this Descriptor is empty!", *this); - valid = false; - } else { - valid = valid & validateName(logger); - } - // ensure that no attribute with the key "name" exists. - if (attributesDescriptor == nullptr) { - logger.error(std::string("Descriptor \"") + getName() + - "\" has no Attribute specification!"); - valid = false; - } else { - if (attributesDescriptor->hasAttribute("name")) { - logger.error( - std::string("Descriptor \"") + getName() + - "\" has an attribute \"name\" which is a reserved word!"); - valid = false; - } - valid = valid & attributesDescriptor->validate(logger); - } - // check that only one FieldDescriptor is of type TREE. - auto fds = Descriptor::getFieldDescriptors(); - bool hasTREE = false; - for (auto fd : fds) { - if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { - if (!hasTREE) { - hasTREE = true; - } else { - logger.error( - std::string("Descriptor \"") + getName() + - "\" has multiple TREE fields, which is not permitted", - *fd); - valid = false; - break; - } - } - } - - // check attributes and the FieldDescriptors - return valid & continueValidationCheckDuplicates(fds, logger); -} - -NodeVector Descriptor::pathTo(Handle target, - Logger &logger) const -{ - bool success = false; - return ousia::pathTo(this, logger, target, success); -} - -std::pair, bool> Descriptor::pathTo( - Handle field, Logger &logger) const -{ - bool success = false; - NodeVector path = ousia::pathTo(this, logger, field, success); - return std::make_pair(path, success); -} - -NodeVector Descriptor::getDefaultFields() const -{ - // TODO: In principle a cast would be nicer here, but for now we copy. - NodeVector nodes = collect(this, [](Handle n) { - if (!n->isa(&RttiTypes::FieldDescriptor)) { - return false; - } - Handle f = n.cast(); - return f->getFieldType() == FieldDescriptor::FieldType::TREE && - f->isPrimitive(); - }); - NodeVector res; - for (auto n : nodes) { - res.push_back(n.cast()); - } - return res; -} - -NodeVector Descriptor::getPermittedChildren() const -{ - // TODO: In principle a cast would be nicer here, but for now we copy. - NodeVector nodes = collect(this, [](Handle n) { - return n->isa(&RttiTypes::StructuredClass); - }); - NodeVector res; - for (auto n : nodes) { - res.push_back(n.cast()); - } - return res; -} - -static ssize_t getFieldDescriptorIndex(const NodeVector &fds, - const std::string &name) -{ - if (fds.empty()) { - return -1; - } - - if (name == DEFAULT_FIELD_NAME) { - if (fds.back()->getFieldType() == FieldDescriptor::FieldType::TREE) { - return fds.size() - 1; - } else { - /* The last field has to be the TREE field. If the last field does - * not have the FieldType TREE no TREE-field exists at all. So we - * return -1. - */ - return -1; - } - } - - for (size_t f = 0; f < fds.size(); f++) { - if (fds[f]->getName() == name) { - return f; - } - } - return -1; -} - -ssize_t Descriptor::getFieldDescriptorIndex(const std::string &name) const -{ - NodeVector fds = getFieldDescriptors(); - return ousia::getFieldDescriptorIndex(fds, name); -} - -ssize_t Descriptor::getFieldDescriptorIndex(Handle fd) const -{ - size_t f = 0; - for (auto &fd2 : getFieldDescriptors()) { - if (fd == fd2) { - return f; - } - f++; - } - return -1; -} - -Rooted Descriptor::getFieldDescriptor( - const std::string &name) const -{ - NodeVector fds = getFieldDescriptors(); - ssize_t idx = ousia::getFieldDescriptorIndex(fds, name); - if (idx != -1) { - return fds[idx]; - } else { - return nullptr; - } -} - -bool Descriptor::addAndSortFieldDescriptor(Handle fd, - Logger &logger) -{ - // only add it if we need to. - auto fds = getFieldDescriptors(); - if (fds.find(fd) == fds.end()) { - invalidate(); - // check if the previous field is a tree field already. - if (!fieldDescriptors.empty() && - fieldDescriptors.back()->getFieldType() == - FieldDescriptor::FieldType::TREE && - fd->getFieldType() != FieldDescriptor::FieldType::TREE) { - // if so we add the new field before the TREE field. - fieldDescriptors.insert(fieldDescriptors.end() - 1, fd); - return true; - } else { - fieldDescriptors.push_back(fd); - } - } - return false; -} - -bool Descriptor::addFieldDescriptor(Handle fd, Logger &logger) -{ - if (fd->getParent() == nullptr) { - fd->setParent(this); - } - return addAndSortFieldDescriptor(fd, logger); -} - -bool Descriptor::moveFieldDescriptor(Handle fd, Logger &logger) -{ - bool sorted = addAndSortFieldDescriptor(fd, logger); - Handle par = fd->getParent(); - if (par != this) { - if (par != nullptr) { - // remove the FieldDescriptor from the old parent. - par.cast()->removeFieldDescriptor(fd); - } - fd->setParent(this); - } - return sorted; -} - -bool Descriptor::copyFieldDescriptor(Handle fd, Logger &logger) -{ - Rooted copy; - if (fd->isPrimitive()) { - copy = Rooted{new FieldDescriptor( - getManager(), fd->getPrimitiveType(), this, fd->getFieldType(), - fd->getName(), fd->isOptional())}; - } else { - /* - * In case of non-primitive FieldDescriptors we also want to copy the - * child references. - */ - copy = Rooted{ - new FieldDescriptor(getManager(), this, fd->getFieldType(), - fd->getName(), fd->isOptional())}; - for (auto c : fd->getChildren()) { - copy->addChild(c); - } - } - return addFieldDescriptor(copy, logger); -} - -bool Descriptor::removeFieldDescriptor(Handle fd) -{ - auto it = fieldDescriptors.find(fd); - if (it != fieldDescriptors.end()) { - invalidate(); - fieldDescriptors.erase(it); - fd->setParent(nullptr); - return true; - } - return false; -} - -std::pair, bool> -Descriptor::createPrimitiveFieldDescriptor(Handle primitiveType, - Logger &logger, - FieldDescriptor::FieldType fieldType, - std::string name, bool optional) -{ - Rooted fd{new FieldDescriptor(getManager(), primitiveType, - this, fieldType, - std::move(name), optional)}; - bool sorted = addFieldDescriptor(fd, logger); - return std::make_pair(fd, sorted); -} - -std::pair, bool> Descriptor::createFieldDescriptor( - Logger &logger, FieldDescriptor::FieldType fieldType, std::string name, - bool optional) -{ - Rooted fd{new FieldDescriptor( - getManager(), this, fieldType, std::move(name), optional)}; - bool sorted = addFieldDescriptor(fd, logger); - return std::make_pair(fd, sorted); -} - -/* Class StructuredClass */ - -StructuredClass::StructuredClass(Manager &mgr, std::string name, - Handle domain, Variant cardinality, - Handle superclass, - bool transparent, bool root) - : Descriptor(mgr, std::move(name), domain), - cardinality(cardinality), - superclass(acquire(superclass)), - subclasses(this), - transparent(transparent), - root(root) -{ - ExceptionLogger logger; - if (superclass != nullptr) { - superclass->addSubclass(this, logger); - } - if (domain != nullptr) { - domain->addStructuredClass(this); - } -} - -bool StructuredClass::doValidate(Logger &logger) const -{ - bool valid = true; - // check if all registered subclasses have this StructuredClass as parent. - for (Handle sub : subclasses) { - if (sub->getSuperclass() != this) { - logger.error(std::string("Struct \"") + sub->getName() + - "\" is registered as subclass of \"" + getName() + - "\" but does not have it as superclass!", - *this); - valid = false; - } - } - // check the cardinality. - if (!cardinality.isCardinality()) { - logger.error(cardinality.toString() + " is not a cardinality!", *this); - valid = false; - } - // check the validity of this superclass. - if (superclass != nullptr) { - valid = valid & superclass->validate(logger); - } - // check the validity as a Descriptor. - /* - * Note that we do not check the validity of all subclasses. This is because - * it will lead to cycles as the subclasses would call validate on their - * superclass, which is this one. - */ - return valid & Descriptor::doValidate(logger); -} - -void StructuredClass::setSuperclass(Handle sup, Logger &logger) -{ - if (superclass == sup) { - return; - } - // remove this subclass from the old superclass. - if (superclass != nullptr) { - superclass->removeSubclass(this, logger); - } - // set the new superclass - superclass = acquire(sup); - invalidate(); - // add this class as new subclass of the new superclass. - if (sup != nullptr) { - sup->addSubclass(this, logger); - // set the attribute descriptor supertype - getAttributesDescriptor()->setParentStructure( - sup->getAttributesDescriptor(), logger); - } else { - getAttributesDescriptor()->setParentStructure(nullptr, logger); - } -} - -bool StructuredClass::isSubclassOf(Handle c) const -{ - if (c == nullptr || superclass == nullptr) { - return false; - } - if (c == superclass) { - return true; - } - return superclass->isSubclassOf(c); -} - -void StructuredClass::addSubclass(Handle sc, Logger &logger) -{ - if (sc == nullptr) { - return; - } - // check if we already have that class. - if (subclasses.find(sc) == subclasses.end()) { - invalidate(); - subclasses.push_back(sc); - } - sc->setSuperclass(this, logger); -} - -void StructuredClass::removeSubclass(Handle sc, Logger &logger) -{ - // if we don't have this subclass we can return directly. - if (sc == nullptr) { - return; - } - auto it = subclasses.find(sc); - if (it == subclasses.end()) { - return; - } - // otherwise we have to erase it. - invalidate(); - subclasses.erase(it); - sc->setSuperclass(nullptr, logger); -} - -Rooted StructuredClass::gatherFieldDescriptors( - NodeVector ¤t, - std::unordered_set &visited, - std::set &overriddenFields, bool hasTREE) const -{ - // this check is to prevent cycles of inheritance to mess up this function. - if (!visited.insert(this).second) { - return nullptr; - } - Rooted mainField; - NodeVector tmp; - // first gather the non-overridden fields. - for (auto f : Descriptor::getFieldDescriptors()) { - if (overriddenFields.insert(f->getName()).second) { - bool isTREE = f->getFieldType() == FieldDescriptor::FieldType::TREE; - if (!isTREE) { - tmp.push_back(f); - } else { - if (!hasTREE) { - hasTREE = true; - mainField = f; - } - } - } - } - // append all non-overridden superclass fields. - - if (superclass != nullptr) { - Rooted super_main_field = - superclass->gatherFieldDescriptors(current, visited, - overriddenFields, hasTREE); - if (!hasTREE) { - mainField = super_main_field; - } - } - // then append all subtree fields of this level. - current.insert(current.end(), tmp.begin(), tmp.end()); - // and return the main field. - return mainField; -} - -NodeVector StructuredClass::getFieldDescriptors() const -{ - // in this case we return a NodeVector of Rooted entries without owner. - NodeVector vec; - std::unordered_set visited; - std::set overriddenFields; - Rooted mainField = - gatherFieldDescriptors(vec, visited, overriddenFields, false); - if (mainField != nullptr) { - vec.push_back(mainField); - } - return vec; -} - -/* Class AnnotationClass */ - -AnnotationClass::AnnotationClass(Manager &mgr, std::string name, - Handle domain) - : Descriptor(mgr, std::move(name), domain) -{ - if (domain != nullptr) { - domain->addAnnotationClass(this); - } -} - -/* Class Domain */ - -void Domain::doResolve(ResolutionState &state) -{ - continueResolveComposita(structuredClasses, structuredClasses.getIndex(), - state); - continueResolveComposita(annotationClasses, annotationClasses.getIndex(), - state); - continueResolveReferences(typesystems, state); - continueResolveReferences(domains, state); -} - -bool Domain::doValidate(Logger &logger) const -{ - // check validity of name, of StructuredClasses, of AnnotationClasses and - // TypeSystems. - return validateName(logger) & - continueValidationCheckDuplicates(structuredClasses, logger) & - continueValidationCheckDuplicates(annotationClasses, logger) & - continueValidationCheckDuplicates(typesystems, logger); -} - -void Domain::doReference(Handle node) -{ - if (node->isa(&RttiTypes::Typesystem)) { - referenceTypesystem(node.cast()); - } - if (node->isa(&RttiTypes::Domain)) { - referenceDomain(node.cast()); - } -} - -RttiSet Domain::doGetReferenceTypes() const -{ - return RttiSet{&RttiTypes::Domain, &RttiTypes::Typesystem}; -} - -void Domain::addStructuredClass(Handle s) -{ - // only add it if we need to. - if (structuredClasses.find(s) == structuredClasses.end()) { - invalidate(); - structuredClasses.push_back(s); - } - Handle par = s->getParent(); - if (par != this) { - if (par != nullptr) { - // remove the StructuredClass from the old parent. - par.cast()->removeStructuredClass(s); - } - s->setParent(this); - } -} - -bool Domain::removeStructuredClass(Handle s) -{ - auto it = structuredClasses.find(s); - if (it != structuredClasses.end()) { - invalidate(); - structuredClasses.erase(it); - s->setParent(nullptr); - return true; - } - return false; -} - -Rooted Domain::createStructuredClass( - std::string name, Variant cardinality, Handle superclass, - bool transparent, bool root) -{ - return Rooted{new StructuredClass( - getManager(), std::move(name), this, cardinality, superclass, - std::move(transparent), std::move(root))}; -} - -void Domain::addAnnotationClass(Handle a) -{ - // only add it if we need to. - if (annotationClasses.find(a) == annotationClasses.end()) { - invalidate(); - annotationClasses.push_back(a); - } - Handle par = a->getParent(); - if (par != this) { - if (par != nullptr) { - // remove the StructuredClass from the old parent. - par.cast()->removeAnnotationClass(a); - } - a->setParent(this); - } -} - -bool Domain::removeAnnotationClass(Handle a) -{ - auto it = annotationClasses.find(a); - if (it != annotationClasses.end()) { - invalidate(); - annotationClasses.erase(it); - a->setParent(nullptr); - return true; - } - return false; -} - -Rooted Domain::createAnnotationClass(std::string name) -{ - return Rooted{ - new AnnotationClass(getManager(), std::move(name), this)}; -} - -/* Type registrations */ - -namespace RttiTypes { -const Rtti FieldDescriptor = - RttiBuilder("FieldDescriptor").parent(&Node); -const Rtti Descriptor = - RttiBuilder("Descriptor").parent(&Node); -const Rtti StructuredClass = - RttiBuilder("StructuredClass") - .parent(&Descriptor) - .composedOf(&FieldDescriptor); -const Rtti AnnotationClass = - RttiBuilder("AnnotationClass").parent(&Descriptor); -const Rtti Domain = RttiBuilder("Domain") - .parent(&RootNode) - .composedOf({&StructuredClass, &AnnotationClass}); -} -} \ No newline at end of file diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp deleted file mode 100644 index 7e10d91..0000000 --- a/src/core/model/Domain.hpp +++ /dev/null @@ -1,1203 +0,0 @@ -/* - 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 . -*/ - -/** - * @file Domain.hpp - * - * This header contains the class hierarchy of descriptor classes for domains. - * Properly connected instances of these classes with a Domain node as root - * describe a semantic Domain in a formal way. It specifies the allowed (tree) - * structure of a document by means of StructuredClasses as well as the allowed - * Annotations by means of AnnotationClasses. - * - * The Structure Description contained in the hierarchy of StructuredClasses is - * equivalent to a context free grammar of a special form. We introduce the - * 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 XML: - * - * \code{.xml} - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * \endcode - * - * Note that we define one field as the TREE (meaning the main or default - * document structure) and one mearly as SUBTREE, relating to supporting - * information. You are not allowed to define more than one field of type - * "TREE". - * - * The translation to a context free grammar is as follows: - * - * \code{.txt} - * 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 - * \endcode - * - * Note that this translation recurs to further nonterminals like SECTION but - * necessarily produces one "book" terminal. Also note that, in principle, - * this grammar translation allows for arbitrarily many children instances of - * 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. - * - * \code{.xml} - * - * - * - * - * - * - * ... - * - * - * - * \endcode - * - * This would change the context free grammar as follows: - * - * \code{.txt} - * BOOK := HEADING BOOK_TREE - * HEADING := PARAGRAPH - * \endcode - * - * 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. An example for that would be the "comment" domain: - * - * \code{.xml} - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * \endcode - * - * Here we have comment annotations, which have a reply tree as sub structure. - * - * @author Benjamin Paaßen (bpaassen@techfak.uni-bielefeld.de) - */ - -#ifndef _OUSIA_MODEL_DOMAIN_HPP_ -#define _OUSIA_MODEL_DOMAIN_HPP_ - -#include -#include - -#include "Node.hpp" -#include "RootNode.hpp" -#include "Typesystem.hpp" - -namespace ousia { - -// Forward declarations -class Rtti; -class Descriptor; -class StructuredClass; -class Domain; - -/** - * Magic field name used to identify the default field. The default field is - * either the tree field or the only subtree field. - */ -static const std::string DEFAULT_FIELD_NAME = "$default"; - -/** - * As mentioned in the description above a FieldDescriptor specifies the - * StructuredClasses that are allowed as children of a StructuredClass or - * AnnotationClass. A field may also be primitive, which means that a proper - * instance of the respective StructuredClass or AnnotationClass must provide - * accordingly typed content without further descending in the Structure - * Hierarchy. - * - * As an example consider the "text" StructuredClass, which might allow - * the actual text content. Here is the according XML: - * - * \code{.xml} - * - * - * - * \endcode - * - */ -class FieldDescriptor : public Node { - friend Descriptor; - -public: - /** - * This enum class contains all possible FieldTypes, meaning either the - * main structure beneath this Descriptor (TREE) or supporting structure - * (SUBTREE) - * - * Note that there may be only one TREE field in a descriptor. - */ - enum class FieldType { TREE, SUBTREE }; - -private: - NodeVector children; - FieldType fieldType; - Owned primitiveType; - bool optional; - bool primitive; - -protected: - bool doValidate(Logger &logger) const override; - -public: - /** - * This is the constructor for primitive fields. - * - * @param mgr is the global Manager instance. - * @param parent is a handle of the Descriptor node that has this - * FieldDescriptor. - * @param primitiveType is a handle to some Type in some Typesystem of which - * one instance is allowed to fill this field. - * @param name is the name of this field. - * @param optional should be set to 'false' is this field needs to be - * filled in order for an instance of the parent - * Descriptor to be valid. - */ - FieldDescriptor(Manager &mgr, Handle primitiveType, - Handle parent, - FieldType fieldType = FieldType::TREE, - std::string name = "", bool optional = false); - - /** - * This is the constructor for non-primitive fields. You have to provide - * children here later on. - * - * @param mgr is the global Manager instance. - * @param parent is a handle of the Descriptor node that has this - * FieldDescriptor. - * @param fieldType is the FieldType of this FieldDescriptor, either - * TREE for the main or default structure or SUBTREE - * for supporting structures. - * @param name is the name of this field. - * @param optional should be set to 'false' is this field needs to be - * filled in order for an instance of the parent - * Descriptor to be valid. - */ - FieldDescriptor(Manager &mgr, Handle parent = nullptr, - FieldType fieldType = FieldType::TREE, - std::string name = "", bool optional = false); - - /** - * Returns a const reference to the NodeVector of StructuredClasses whose - * instances are allowed as children in the StructureTree of instances of - * this field. - * - * @return a const reference to the NodeVector of StructuredClasses whose - * instances are allowed as children in the StructureTree of instances of - * this field. - */ - const NodeVector &getChildren() const { return children; } - - /** - * Returns all StructuredClasses whose instances are allowed as children in - * the Structure Tree of instances of this field including subclasses of - * children, which are allowed directly. - * - * @return all StructuredClasses whose instances are allowed as children in - * the Structure Tree of instances of this field including subclasses of - * children, which are allowed directly. - */ - NodeVector getChildrenWithSubclasses() const; - - /** - * Adds a StructuredClass whose instances shall be allowed as children in - * the StructureTree of instances of this field. - */ - void addChild(Handle c) - { - invalidate(); - children.push_back(c); - } - - /** - * Adds multiple StructuredClasses whose instances shall be allowed as - * children in the StructureTree of instances of this field. - */ - void addChildren(const std::vector> &cs) - { - invalidate(); - children.insert(children.end(), cs.begin(), cs.end()); - } - - /** - * Removes the given StructuredClass from the list of children of this - * FieldDescriptor. - * - * @param c some StructuredClass that shan't be a child of this - * FieldDescriptor anymore. - * @return true if the FieldDescriptor contained this child and false if it - * did not. - */ - bool removeChild(Handle c); - - /** - * Returns the type of this field (not to be confused with the primitive - * type of this field). - * - * @return the type of this field. - */ - FieldType getFieldType() const { return fieldType; } - /** - * Sets the type of this field (not to be confused with the primitive type - * of this field). - * - * @param ft is the new type of this field. - */ - void setFieldType(const FieldType &ft) - { - invalidate(); - fieldType = ft; - } - - /** - * Returns if this field is primitive. - * - * @return true if and only if this field is primitive. - */ - bool isPrimitive() const { return primitive; } - - /** - * Returns the primitive type of this field, which is only allowed to be - * set if the type of this field is PRIMITIVE. - * - * @return the primitive type of this field. - */ - Rooted getPrimitiveType() const { return primitiveType; } - - /** - * Sets the primitive type of this field, which is only allowed to be - * set if the type of this field is PRIMITIVE. - * - * @param t is the new primitive type of this field- - */ - void setPrimitiveType(Handle t) - { - invalidate(); - primitiveType = acquire(t); - } - - /** - * Returns true if and only if this field is optional. - * - * @return true if and only if this field is optional. - */ - bool isOptional() const { return optional; } - - /** - * Specifies whether this field shall be optional. - * - * @param o should be true if and only if this field should be optional. - */ - void setOptional(bool o) - { - invalidate(); - optional = std::move(o); - } - - /** - * This tries to construct the shortest possible path of this Descriptor - * to the given child Descriptor. Note that this method has the problem that - * an empty return path does NOT strictly imply that no such path could - * be constructed: We also return an empty vector if the given - * Descriptor is a direct child. Therefore we also return a bool value - * indicating that the path is valid or not. - * - * Implicitly this does a breadth-first search on the graph of - * StructuredClasses that are transparent. It also takes care of cycles. - * - * @param childDescriptor is a supposedly valid child Descriptor of this - * Descriptor. - * @return a tuple containing a path of FieldDescriptors and - * StructuredClasses between this Descriptor and the - * input Descriptor and a bool value indicating if - * the construction was successful. - * - */ - std::pair, bool> pathTo( - Handle childDescriptor, Logger &logger) const; - /** - * This tries to construct the shortest possible path of this Descriptor - * to the given FieldDescriptor. Note that this method has the problem that - * an empty return path does NOT strictly imply that no such path could - * be constructed: We also return an empty vector if the given - * FieldDescriptor is a direct child. Therefore we also return a bool value - * indicating that the path is valid or not. - * - * - * Implicitly this does a breadth-first search on the graph of - * StructuredClasses that are transparent. It also takes care of cycles. - * - * @param field is a FieldDescriptor that may be allowed as child of this - * Descriptor. - * @return a path of FieldDescriptors and StructuredClasses between - * this Descriptor and the input FieldDescriptor or an empty - * vector if no such path could be constructed. - */ - NodeVector pathTo(Handle field, - Logger &logger) const; - - /** - * Returns a vector of all TREE fields that are allowed as structure tree - * children of an instance of this Descriptor. This also makes use of - * transparency. - * The list is sorted by the number of transparent elements that have to be - * constructed to arrive at the respective FieldDescriptor. - * - * @return a vector of all TREE fields that are allowed as structure tree - * children of an instance of this Descriptor. - */ - NodeVector getDefaultFields() const; -}; - -/** - * This is a super class for StructuredClasses and AnnotationClasses and is, - * in itself, not supposed to be instantiated. It defines that both, Annotations - * and StructuredEntities, may have attributes and fields. For more information - * on fields please have a look at the header documentation as well as the - * documentation of the FieldDescriptor class. - * - * Attributes are primitive content stored in a key-value fashion. Therefore - * the attribute specification of a descriptor is done by referencing an - * appropriate StructType that contains all permitted keys and value types. - * - * In XML terms the difference between primitive fields and attributes can be - * explained as the difference between node attributes and node children. - * Consider the XML - * - * \code{.xml} - * - * value - * - * \endcode - * - * key="value" inside the A-node would be an attribute, while value - * would be a primitive field. While equivalent in XML the semantics are - * different: An attribute describes indeed attributes, features of one single - * node whereas a primitive field describes the _content_ of a node. - * - */ -class Descriptor : public Node { - friend FieldDescriptor; - -private: - Owned attributesDescriptor; - NodeVector fieldDescriptors; - - bool addAndSortFieldDescriptor(Handle fd, Logger &logger); - -protected: - void doResolve(ResolutionState &state) override; - - bool doValidate(Logger &logger) const override; - -public: - Descriptor(Manager &mgr, std::string name, Handle domain) - : Node(mgr, std::move(name), domain), - attributesDescriptor(acquire(new StructType(mgr, "", nullptr))), - fieldDescriptors(this) - { - } - - /** - * Returns a reference to the StructType that specifies the attribute keys - * as well as value domains for this Descriptor. - * - * @return a reference to the StructType that specifies the attribute keys - * as well as value domains for this Descriptor. - */ - Rooted getAttributesDescriptor() const - { - return attributesDescriptor; - } - - /** - * Returns the NodeVector of all FieldDescriptors of this Descriptor. - * - * @return the NodeVector of all FieldDescriptors of this Descriptor. - */ - virtual NodeVector getFieldDescriptors() const - { - return fieldDescriptors; - } - - /** - * Returns the index of the FieldDescriptor with the given name or -1 if no - * such FieldDescriptor was found. - * - * @param name the name of a FieldDescriptor. - - * @return the index of the FieldDescriptor with the given name or -1 if - * no such FieldDescriptor was found. - */ - ssize_t getFieldDescriptorIndex( - const std::string &name = DEFAULT_FIELD_NAME) const; - /** - * Returns the index of the given FieldDescriptor or -1 of the given - * FieldDescriptor is not registered at this Descriptor. - * - * @param fd a FieldDescriptor. - - * @return the index of the given FieldDescriptor or -1 of the given - * FieldDescriptor is not registered at this Descriptor. - */ - ssize_t getFieldDescriptorIndex(Handle fd) const; - /** - * Returns the FieldDescriptor with the given name. - * - * @param name the name of a FieldDescriptor. - - * @return the FieldDescriptor with the given name or a nullptr if no - * such FieldDescriptor was found. - */ - Rooted getFieldDescriptor( - const std::string &name = DEFAULT_FIELD_NAME) const; - - /** - * This returns true if this Descriptor has a FieldDescriptor with the - * given name. - * - * @param name the name of a FieldDescriptor. - - * @return true if this Descriptor has a FieldDescriptor with the given - * name - */ - bool hasField(const std::string &fieldName = DEFAULT_FIELD_NAME) const - { - return getFieldDescriptorIndex(fieldName) != -1; - } - - /** - * Adds the given FieldDescriptor to this Descriptor. This also sets the - * parent of the given FieldDescriptor if it is not set yet. - * - * @param fd is a FieldDescriptor. - * @return returns true if the given FieldDescriptor was not added at the - * end one place before because a TREE field already existed and - * the TREE field has to be at the end. - */ - bool addFieldDescriptor(Handle fd, Logger &logger); - - /** - * Adds the given FieldDescriptor to this Descriptor. This also sets the - * parent of the given FieldDescriptor if it is not set to this Descriptor - * already and removes it from the old parent Descriptor. - * - * @param fd is a FieldDescriptor. - * @return returns true if the given FieldDescriptor was not added at the - * end one place before because a TREE field already existed and - * the TREE field has to be at the end. - */ - bool moveFieldDescriptor(Handle fd, Logger &logger); - - /** - * Copies a FieldDescriptor that belongs to another Descriptor to this - * Descriptor. - * - * @param fd some FieldDescriptor belonging to another Descriptor. - * @return returns true if the given FieldDescriptor was not added at the - * end one place before because a TREE field already existed and - * the TREE field has to be at the end. - */ - bool copyFieldDescriptor(Handle fd, Logger &logger); - - /** - * Removes the given FieldDescriptor from this Descriptor. This also sets - * the parent of the given FieldDescriptor to null. - * - * @param fd is a FieldDescriptor. - * @return true if the FieldDescriptor was removed and false if this - * Descriptor did not have the given FieldDescriptor as child. - */ - bool removeFieldDescriptor(Handle fd); - - /** - * This creates a new primitive FieldDescriptor and adds it to this - * Descriptor. - * - * @param primitiveType is a handle to some Type in some Typesystem of which - * one instance is allowed to fill this field. - * @param name is the name of this field. - * @param optional should be set to 'false' is this field needs to be - * filled in order for an instance of the parent - * Descriptor to be valid. - * - * @return the newly created FieldDescriptor and a bool - * indicating whether the order of FieldDescriptors had - * to be changed for the TREE field to be in the last - * spot. - */ - std::pair, bool> createPrimitiveFieldDescriptor( - Handle primitiveType, Logger &logger, - FieldDescriptor::FieldType fieldType = FieldDescriptor::FieldType::TREE, - std::string name = "", bool optional = false); - - /** - * This creates a new primitive FieldDescriptor and adds it to this - * Descriptor. - * - * @param fieldType is the FieldType of this FieldDescriptor, either - * TREE for the main or default structure or SUBTREE - * for supporting structures. - * @param name is the name of this field. - * @param optional should be set to 'false' is this field needs to be - * filled in order for an instance of the parent - * Descriptor to be valid. - * - * @return the newly created FieldDescriptor and a bool - * indicating whether the order of FieldDescriptors had - * to be changed for the TREE field to be in the last - * spot. - */ - std::pair, bool> createFieldDescriptor( - Logger &logger, - FieldDescriptor::FieldType fieldType = FieldDescriptor::FieldType::TREE, - std::string name = "", bool optional = false); - - /** - * This tries to construct the shortest possible path of this Descriptor - * to the given child Descriptor. As an example consider the book domain - * from above. - * - * First consider the call book->pathTo(chapter). This is an easy example: - * Our path just contains a reference to the default field of book, because - * a chapter may be directly added to the main field of book. - * - * Second consider the call book->pathTo(text). This is somewhat more - * complicated, but it is still a valid request, because we can construct - * the path: {book_main_field, paragraph, paragraph_main_field}. - * This is only valid because paragraph is transparent. - * - * What about the call book->pathTo(section)? This will lead to an empty - * return path (= invalid). We could, of course, in principle construct - * a path between book and section (via chapter), but chapter is not - * transparent. Therefore that path is not allowed. - * - * Implicitly this does a breadth-first search on the graph of - * StructuredClasses that are transparent. It also takes care of cycles. - * - * @param childDescriptor is a supposedly valid child Descriptor of this - * Descriptor. - * @return either a path of FieldDescriptors and - * StructuredClasses between this Descriptor and - * the input StructuredClass or an empty vector if - * no such path can be constructed. - * - */ - NodeVector pathTo(Handle childDescriptor, - Logger &logger) const; - /** - * This tries to construct the shortest possible path of this Descriptor - * to the given FieldDescriptor. Note that this method has the problem that - * an empty return path does NOT strictly imply that no such path could - * be constructed: We also return an empty vector if the given - * FieldDescriptor is a direct child. Therefore we also return a bool value - * indicating that the path is valid or not. - * - * - * Implicitly this does a breadth-first search on the graph of - * StructuredClasses that are transparent. It also takes care of cycles. - * - * @param field is a FieldDescriptor that may be allowed as child of this - * Descriptor. - * @return returns a tuple containing a path of FieldDescriptors and - * StructuredClasses between this Descriptor and the input - * FieldDescriptor and a bool value indicating if the - * construction was successful. - */ - std::pair, bool> pathTo(Handle field, - Logger &logger) const; - - /** - * Returns a vector of all TREE fields that are allowed as structure tree - * children of an instance of this Descriptor. This also makes use of - * transparency. - * The list is sorted by the number of transparent elements that have to be - * constructed to arrive at the respective FieldDescriptor. - * - * @return a vector of all TREE fields that are allowed as structure tree - * children of an instance of this Descriptor. - */ - NodeVector getDefaultFields() const; - - /** - * Returns a vector of all StructuredClasses that are allowed as children - * of an instance of this Descriptor in the structure tree. This also makes - * use of transparency. - * The list is sorted by the number of transparent elements that have to be - * constructed to arrive at the respective FieldDescriptor. - * - * @return a vector of all StructuredClasses that are allowed as children - * of an instance of this Descriptor in the structure tree. - */ - NodeVector getPermittedChildren() const; -}; -/* - * TODO: We should discuss Cardinalities one more time. Is it smart to define - * cardinalities independent of context? Should we not have at least have the - * possibility to define it context-dependently? - */ - -/** - * A StructuredClass specifies nodes in the StructureTree of a document that - * implements this domain. For more information on the StructureTree please - * 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 the - * example of the "heading" domain from the header documentation again: - * - * \code{.xml} - * - * - * - * - * - * - * - * - * - * - * ... - * - * - * - * - * - * - * \endcode - * - * 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 - * they provide the most convenient mechanism to extend existing domains - * without having to rewrite them. - * - * Another important factor is the 'transparent' flag. Transparent - * StructureClasses may be implicitly constructed in the document graph. - * If we go back to our example a user would (without transparency) have to - * explicitly declare: - * - * \code{.xml} - * - *
- * Text. - *
- *
- * \endcode - * - * But in our mind the document - * - * \code{.xml} - * - *
- * Text. - *
- *
- * \endcode - * - * Is already sufficiently specific. We can infer that a paragraph should be - * wrapped around "Text.". Therefore we set the 'transparent' flag of the - * "paragraph" StructuredClass to true. Please note that such inferences - * become increasingly complicated when children of transparent - * StructuredClasses are allowed to be transparent as well. So use with care. - * - * Finally we allow StructuredClasses to inherit attributes of other - * StructuredClasses. Inheritance also implies that instance of the inheriting - * class can be used wherever an instance of the inherited class is allowed. - * Inheritance therefore also goes for fields. - */ -class StructuredClass : public Descriptor { - friend Domain; - -private: - const Variant cardinality; - Owned superclass; - NodeVector subclasses; - bool transparent; - bool root; - - /** - * Helper method for getFieldDescriptors. - */ - Rooted gatherFieldDescriptors( - NodeVector ¤t, - std::unordered_set &visited, - std::set &overriddenFields, bool hasTREE) const; - -protected: - bool doValidate(Logger &logger) const override; - -public: - /** - * The constructor for a StructuredClass. - * - * @param mgr is the current Manager. - * @param name is the name of the StructuredClass. - * @param domain is the Domain this StructuredClass belongs - * to. - * @param cardinality specifies how often an element of this type - * may occur at a specific point in the - * StructureTree. For example: A document should - * have at least one author. This is set to * - * per default, meaning that any number of - * of instances is valid, including zero. - * @param superclass references a parent StructuredClass. Please - * look for more information on inheritance in - * the class documentation above. The default is - * a null reference, meaning no super class. - * The constructor automatically registers this - * class as a subclass at the super class. - * @param transparent specifies whether this StructuredClass is - * transparent. For more information on - * transparency please refer to the class - * documentation above. The default is false. - * @param root specifies whether this StructuredClass is - * allowed to be at the root of a Document. - */ - StructuredClass(Manager &mgr, std::string name, - Handle domain = nullptr, - Variant cardinality = Cardinality::any(), - Handle superclass = nullptr, - bool transparent = false, bool root = false); - - /** - * Returns the Cardinality of this StructuredClass (as a RangeSet). - * - * @return the Cardinality of this StructuredClass (as a RangeSet). - */ - const Variant &getCardinality() const { return cardinality; } - - /** - * Returns the superclass of this StructuredClass. This is not the same as - * the parents in the Structure Tree! - * - * @return the superclass of this StructuredClass. - */ - Rooted getSuperclass() const { return superclass; } - - /** - * Sets the superclass of this StructuredClass. This is not the same as - * the parents in the Structure Tree! - * - * This will also register this class as a subclass at the given superclass - * and unregister it at the previous superclass. - * - * It will also set the parent for this Descriptors AttributesDescriptor. - * - * @param sup some StructuredClass that shall be the new superclass of - * this StructuredClass. - * @param logger is some logger. Errors during setting the parent for this - * Descriptors AttributesDescriptor will be written into this - * logger. - */ - void setSuperclass(Handle sup, Logger &logger); - - /** - * Returns true if this class is a subclass of the given class. It does not - * return true if the other class is equal to the given class. - * - * @param c is another class that might or might not be a superclass of this - * one - * @return true if this class is a subclass of the given class. - * - */ - bool isSubclassOf(Handle c) const; - - /** - * Returns the StructuredClasses that are subclasses of this class. This - * is the inverted version of isa, meaning: each class c that has a isa - * relationship to this class is part of the returned vector. - * - * Note that the order of subclasses is not strictly defined. - * - * You are not allowed to add subclasses directly to the vector. When you - * construct a new StructuredClass with a non-empty isa-handle it will - * automatically register as subclass at the super class. - * - * @return the StructuredClasses that are subclasses of this class. - */ - const NodeVector &getSubclasses() const - { - return subclasses; - } - - /** - * Adds a subclass to this StructuredClass. This also calls setSuperclass - * on the given subclass. - * - * @param sc is some StructuredClass. - * @param logger is some logger. Errors during setting the parent for the - * new subclasses AttributesDescriptor will be written into - * this logger. - */ - void addSubclass(Handle sc, Logger &logger); - - /** - * Removes a subclass from this StructuredClass. This also calls - * setSuperclass(nullptr) on the given subclass. - * - * @param sc is some StructuredClass. - * @param logger is some logger. Errors during setting the parent for the - * removed subclasses AttributesDescriptor will be written - * into this logger. - */ - void removeSubclass(Handle sc, Logger &logger); - - /** - * Returns a NodeVector of all FieldDescriptors of - * this StructuredClass. This also merges the FieldDescriptors directly - * belonging to this StructuredClass with all FieldDescritptors of its - * Superclass (and so on recurvively). The order of field descriptors is - * as follows: - * 1.) non-overridden SUBTREE FieldDescriptors of super classes. - * 2.) SUBTREE FieldDescriptors of this class. - * 3.) TREE FieldDescriptor (either inherited from super class or direct) - * - * @return a NodeVector of all FieldDescriptors of this StructuredClass. - */ - NodeVector getFieldDescriptors() const override; - - bool isTransparent() const { return transparent; } - - void setTransparent(bool t) - { - invalidate(); - transparent = std::move(t); - } - - bool hasRootPermission() const { return root; } - - void setRootPermission(bool r) - { - invalidate(); - root = std::move(r); - } -}; - -/** - * An AnnotationClass defines allowed Annotations. For more information on - * Annotations please refer to the Document.hpp. - * - * This class has no special properties and is in essence just a Descriptor. - */ -class AnnotationClass : public Descriptor { - friend Domain; - -public: - /** - * The constructor for a new AnnotationClass. Note that you have to add - * the FieldDescriptors to it later on. - * - * @param mgr is the Manager instance. - * @param name is a name for this AnnotationClass that will - * be used for later references to this - * AnnotationClass. - * @param domain is the Domain this AnnotationClass belongs - * to. - */ - AnnotationClass(Manager &mgr, std::string name, Handle domain); -}; - -/** - * A Domain node specifies which StructuredClasses and which AnnotationClasses - * are part of this domain. TODO: Do we want to be able to restrict Annotations - * to certain Structures? - */ -class Domain : public RootNode { - friend StructuredClass; - friend AnnotationClass; - -private: - NodeVector structuredClasses; - NodeVector annotationClasses; - NodeVector typesystems; - NodeVector domains; - -protected: - void doResolve(ResolutionState &state) override; - bool doValidate(Logger &logger) const override; - void doReference(Handle node) override; - RttiSet doGetReferenceTypes() const override; - -public: - /** - * The constructor for a new domain. Note that this is an empty Domain and - * still has to be filled with StructuredClasses and AnnotationClasses. - * - * @param mgr is the Manager instance. - * @param name is a name for this domain which will be used for later - * references to this Domain. - */ - Domain(Manager &mgr, std::string name = "") - : RootNode(mgr, std::move(name), nullptr), - structuredClasses(this), - annotationClasses(this), - typesystems(this), - domains(this) - { - } - - /** - * The constructor for a new domain. Note that this is an empty Domain and - * still has to be filled with StructuredClasses and AnnotationClasses. - * - * @param mgr is the Manager instance. - * @param sys is the SystemTypesystem instance. - * @param name is a name for this domain which will be used for later - * references to this Domain. - */ - Domain(Manager &mgr, Handle sys, std::string name = "") - : Domain(mgr, std::move(name)) - { - referenceTypesystem(sys); - } - - /** - * Creates a new Domain and returns it. - * - * @param mgr is the Manager instance. - * @param name is a name for this domain which will be used for later - * references to this Domain. - */ - static Rooted createEmptyDomain(Manager &mgr, std::string name) - { - return Rooted{new Domain(mgr, std::move(name))}; - } - - /** - * Returns a const reference to the NodeVector of StructuredClasses that are - * part of this Domain. - * - * @return a const reference to the NodeVector of StructuredClasses that are - * part of this Domain. - */ - const NodeVector &getStructureClasses() const - { - return structuredClasses; - } - /** - * Adds a StructuredClass to this domain. This also sets the parent of the - * given StructuredClass if it is not set to this Domain already and removes - * it from the old Domain. - * - * @param s is some StructuredClass. - */ - void addStructuredClass(Handle s); - - /** - * Removes a StructuredClass from this domain. This also sets the parent of - * the given StructuredClass to null. - * - * @param s is some StructuredClass. - * @return true if the given StructuredClass was removed and false if this - * Domain did not have the given StructuredClass as child. - */ - bool removeStructuredClass(Handle s); - - /** - * This creates a new StructuredClass and appends it to this Domain. - * - * @param name is the name of the StructuredClass. - * @param cardinality specifies how often an element of this type - * may occur at a specific point in the - * StructureTree. For example: A document should - * have at least one author. This is set to * - * per default, meaning that any number of - * of instances is valid, including zero. - * @param superclass references a parent StructuredClass. Please - * look for more information on inheritance in - * the class documentation above. The default is - * a null reference, meaning no super class. - * The constructor automatically registers this - * class as a subclass at the super class. - * @param transparent specifies whether this StructuredClass is - * transparent. For more information on - * transparency please refer to the class - * documentation above. The default is false. - * @param root specifies whether this StructuredClass is - * allowed to be at the root of a Document. - * - * @return the newly created StructuredClass. - */ - Rooted createStructuredClass( - std::string name, Variant cardinality = Cardinality::any(), - Handle superclass = nullptr, bool transparent = false, - bool root = false); - - /** - * Returns a const reference to the NodeVector of AnnotationClasses that are - * part of this Domain. - * - * @return a const reference to the NodeVector of AnnotationClasses that are - * part of this Domain. - */ - const NodeVector &getAnnotationClasses() const - { - return annotationClasses; - } - /** - * Adds an AnnotationClass to this domain. This also sets the parent of the - * given AnnotationClass if it is not set to this Domain already and removes - * it from the old Domain. - * - * @param a is some AnnotationClass. - */ - void addAnnotationClass(Handle a); - - /** - * Removes a AnnotationClass from this domain. This also sets the parent of - * the given AnnotationClass to null. - * - * @param a is some AnnotationClass. - * @return true if the given AnnotationClass was removed and false if this - * Domain did not have the given AnnotationClass as child. - */ - bool removeAnnotationClass(Handle a); - - /** - * This creates a new AnnotationClass and appends it to this Domain. - * - * @param name is a name for this AnnotationClass that will - * be used for later references to this - * AnnotationClass. - */ - Rooted createAnnotationClass(std::string name); - - /** - * Returns a const reference to the NodeVector of TypeSystems that are - * references in this Domain. - * - * @return a const reference to the NodeVector of TypeSystems that are - * references in this Domain. - */ - const NodeVector &getTypesystems() const { return typesystems; } - - /** - * Adds a Typesystem reference to this Domain. - */ - void referenceTypesystem(Handle t) { typesystems.push_back(t); } - - /** - * Adds multiple Typesystem references to this Domain. - */ - void referenceTypesystems(const std::vector> &ts) - { - typesystems.insert(typesystems.end(), ts.begin(), ts.end()); - } - - /** - * Adds a Domain reference to this Domain. - */ - void referenceDomain(Handle d) { domains.push_back(d); } - - /** - * Adds multiple Domain references to this Domain. - */ - void referenceDomains(const std::vector> &ds) - { - domains.insert(domains.end(), ds.begin(), ds.end()); - } -}; - -namespace RttiTypes { - -extern const Rtti FieldDescriptor; -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/core/model/Node.hpp b/src/core/model/Node.hpp index fe8db16..0567e67 100644 --- a/src/core/model/Node.hpp +++ b/src/core/model/Node.hpp @@ -88,7 +88,7 @@ struct ResolutionResult { /** * Root node of the subtree in which the node was found. This e.g. points to - * the Domain in which a Structure was defined or the Typesystem in which a + * the Ontology in which a Structure was defined or the Typesystem in which a * Type was defined. May be nullptr. */ Rooted resolutionRoot; @@ -119,7 +119,7 @@ class ResolutionState; /** * The Node class builds the base class for any Node within the DOM graph. A - * node may either be a descriptive node (such as a domain description etc.) + * node may either be a descriptive node (such as a ontology description etc.) * or a document element. Each node is identified by acharacteristic name and * a parent element. Note that the node name is not required to be unique. Nodes * without parent are considered root nodes. diff --git a/src/core/model/Ontology.cpp b/src/core/model/Ontology.cpp new file mode 100644 index 0000000..8829139 --- /dev/null +++ b/src/core/model/Ontology.cpp @@ -0,0 +1,981 @@ +/* + 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 "Ontology.hpp" + +namespace ousia { + +/* Helper Functions */ + +struct PathState { + std::shared_ptr pred; + Node *node; + size_t length; + + PathState(std::shared_ptr pred, Node *node) + : pred(pred), node(node) + { + if (pred == nullptr) { + length = 1; + } else { + length = pred->length + 1; + } + } +}; + +static void constructPath(std::shared_ptr state, + NodeVector &vec) +{ + if (state->pred != nullptr) { + constructPath(state->pred, vec); + } + vec.push_back(state->node); +} + +static NodeVector pathTo(const Node *start, Logger &logger, + Handle target, bool &success) +{ + success = false; + // shortest path. + NodeVector shortest; + // state queue for breadth-first search. + std::queue> states; + if (start->isa(&RttiTypes::Descriptor)) { + const Descriptor *desc = static_cast(start); + // initially put every field descriptor on the queue. + NodeVector fields = desc->getFieldDescriptors(); + + for (auto fd : fields) { + if (fd == target) { + // if we have found the target directly, return without search. + success = true; + return shortest; + } + if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { + states.push(std::make_shared(nullptr, fd.get())); + } + } + } else { + const FieldDescriptor *field = + static_cast(start); + // initially put every child and its subclasses to the queue. + for (auto c : field->getChildrenWithSubclasses()) { + // if we have found the target directly, return without search. + if (c == target) { + success = true; + return shortest; + } + if (c->isTransparent()) { + states.push(std::make_shared(nullptr, c.get())); + } + } + } + // set of visited nodes. + std::unordered_set visited; + while (!states.empty()) { + std::shared_ptr current = states.front(); + states.pop(); + // do not proceed if this node was already visited. + if (!visited.insert(current->node).second) { + continue; + } + // also do not proceed if we can't get better than the current shortest + // path anymore. + if (!shortest.empty() && current->length > shortest.size()) { + continue; + } + + bool fin = false; + if (current->node->isa(&RttiTypes::StructuredClass)) { + const StructuredClass *strct = + static_cast(current->node); + + // look through all fields. + NodeVector fields = strct->getFieldDescriptors(); + for (auto fd : fields) { + // if we found our target, break off the search in this branch. + if (fd == target) { + fin = true; + continue; + } + // only continue in the TREE field. + if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { + states.push(std::make_shared(current, fd.get())); + } + } + } else { + // otherwise this is a FieldDescriptor. + const FieldDescriptor *field = + static_cast(current->node); + // and we proceed by visiting all permitted children. + for (auto c : field->getChildrenWithSubclasses()) { + // if we found our target, break off the search in this branch. + if (c == target) { + fin = true; + continue; + } + // We only allow to continue our path via transparent children. + if (c->isTransparent()) { + states.push(std::make_shared(current, c.get())); + } + } + } + // check if we are finished. + if (fin) { + success = true; + // if so we look if we found a shorter path than the current minimum + if (shortest.empty() || current->length < shortest.size()) { + NodeVector newPath; + constructPath(current, newPath); + shortest = newPath; + } else if (current->length == shortest.size()) { + // if the length is the same the result is ambigous and we log + // an error. + NodeVector newPath; + constructPath(current, newPath); + logger.error( + std::string("Can not unambigously create a path from \"") + + start->getName() + "\" to \"" + target->getName() + "\"."); + logger.note("Dismissed the path:", SourceLocation{}, + MessageMode::NO_CONTEXT); + for (auto n : newPath) { + logger.note(n->getName()); + } + } + } + } + return shortest; +} + +template +static NodeVector collect(const Node *start, F match) +{ + // result + NodeVector res; + // queue for breadth-first search of graph. + std::queue> q; + // put the initial node on the stack. + q.push(const_cast(start)); + // set of visited nodes. + std::unordered_set visited; + while (!q.empty()) { + Rooted n = q.front(); + q.pop(); + // do not proceed if this node was already visited. + if (!visited.insert(n.get()).second) { + continue; + } + + if (n->isa(&RttiTypes::StructuredClass)) { + Rooted strct = n.cast(); + + // look through all fields. + NodeVector fields = strct->getFieldDescriptors(); + for (auto fd : fields) { + // note matches. + if (match(fd)) { + res.push_back(fd); + } + // only continue in the TREE field. + if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { + q.push(fd); + } + } + } else { + // otherwise this is a FieldDescriptor. + Rooted field = n.cast(); + // and we proceed by visiting all permitted children. + for (auto c : field->getChildrenWithSubclasses()) { + // note matches. + if (match(c)) { + res.push_back(c); + } + // We only continue our search via transparent children. + if (c->isTransparent()) { + q.push(c); + } + } + } + } + return res; +} + +/* Class FieldDescriptor */ + +FieldDescriptor::FieldDescriptor(Manager &mgr, Handle primitiveType, + Handle parent, FieldType fieldType, + std::string name, bool optional) + : Node(mgr, std::move(name), parent), + children(this), + fieldType(fieldType), + primitiveType(acquire(primitiveType)), + optional(optional), + primitive(true) +{ +} + +FieldDescriptor::FieldDescriptor(Manager &mgr, Handle parent, + FieldType fieldType, std::string name, + bool optional) + : Node(mgr, std::move(name), parent), + children(this), + fieldType(fieldType), + optional(optional), + primitive(false) +{ +} + +bool FieldDescriptor::doValidate(Logger &logger) const +{ + bool valid = true; + // check parent type + if (getParent() == nullptr) { + logger.error(std::string("Field \"") + getName() + "\" has no parent!", + *this); + valid = false; + } else if (!getParent()->isa(&RttiTypes::Descriptor)) { + logger.error(std::string("The parent of Field \"") + getName() + + "\" is not a descriptor!", + *this); + valid = false; + } + // check name + if (getName().empty()) { + if (fieldType != FieldType::TREE) { + logger.error(std::string("Field \"") + getName() + + "\" is not the main field but has an empty name!", + *this); + valid = false; + } + } else { + valid = valid & validateName(logger); + } + + // check consistency of FieldType with the rest of the FieldDescriptor. + if (primitive) { + if (children.size() > 0) { + logger.error(std::string("Field \"") + getName() + + "\" is supposed to be primitive but has " + "registered child classes!", + *this); + valid = false; + } + if (primitiveType == nullptr) { + logger.error(std::string("Field \"") + getName() + + "\" is supposed to be primitive but has " + "no primitive type!", + *this); + valid = false; + } + } else { + if (primitiveType != nullptr) { + logger.error(std::string("Field \"") + getName() + + "\" is supposed to be non-primitive but has " + "a primitive type!", + *this); + valid = false; + } + // if this is not a primitive field we require at least one child. + if (children.empty()) { + logger.error(std::string("Field \"") + getName() + + "\" is non primitive but does not allow children!", + *this); + valid = false; + } + } + /* + * we are not allowed to call the validation functions of each child because + * this might lead to cycles. What we should do, however, is to check if + * there are duplicates. + */ + std::set names; + for (Handle c : getChildrenWithSubclasses()) { + if (!names.insert(c->getName()).second) { + logger.error(std::string("Field \"") + getName() + + "\" had multiple children with the name \"" + + c->getName() + "\"", + *this); + valid = false; + } + } + + return valid; +} + +static void gatherSubclasses( + std::unordered_set& visited, + NodeVector &res, Handle strct) +{ + // this check is to prevent cycles. + if (!visited.insert(strct.get()).second) { + return; + } + for (auto sub : strct->getSubclasses()) { + // this check is to prevent cycles. + if(visited.count(sub.get())){ + continue; + } + res.push_back(sub); + gatherSubclasses(visited, res, sub); + } +} + +NodeVector FieldDescriptor::getChildrenWithSubclasses() const +{ + std::unordered_set visited; + NodeVector res; + for (auto c : children) { + res.push_back(c); + gatherSubclasses(visited, res, c); + } + return res; +} + +bool FieldDescriptor::removeChild(Handle c) +{ + auto it = children.find(c); + if (it != children.end()) { + invalidate(); + children.erase(it); + return true; + } + return false; +} + +std::pair, bool> FieldDescriptor::pathTo( + Handle childDescriptor, Logger &logger) const +{ + bool success = false; + NodeVector path = + ousia::pathTo(this, logger, childDescriptor, success); + return std::make_pair(path, success); +} +NodeVector FieldDescriptor::pathTo(Handle field, + Logger &logger) const +{ + bool success = false; + return ousia::pathTo(this, logger, field, success); +} +NodeVector FieldDescriptor::getDefaultFields() const +{ + // TODO: In principle a cast would be nicer here, but for now we copy. + NodeVector nodes = collect(this, [](Handle n) { + if (!n->isa(&RttiTypes::FieldDescriptor)) { + return false; + } + Handle f = n.cast(); + return f->getFieldType() == FieldDescriptor::FieldType::TREE && + f->isPrimitive(); + }); + NodeVector res; + for (auto n : nodes) { + res.push_back(n.cast()); + } + return res; +} + +/* Class Descriptor */ + +void Descriptor::doResolve(ResolutionState &state) +{ + const NodeVector &attributes = + attributesDescriptor->getAttributes(); + continueResolveComposita(attributes, attributes.getIndex(), state); + continueResolveComposita(fieldDescriptors, fieldDescriptors.getIndex(), + state); +} + +bool Descriptor::doValidate(Logger &logger) const +{ + bool valid = true; + // check parent type + if (getParent() == nullptr) { + logger.error( + std::string("Descriptor \"") + getName() + "\" has no parent!", + *this); + valid = false; + } else if (!getParent()->isa(&RttiTypes::Ontology)) { + logger.error(std::string("The parent of Descriptor \"") + getName() + + "\" is not a Ontology!", + *this); + valid = false; + } + // check name + if (getName().empty()) { + logger.error("The name of this Descriptor is empty!", *this); + valid = false; + } else { + valid = valid & validateName(logger); + } + // ensure that no attribute with the key "name" exists. + if (attributesDescriptor == nullptr) { + logger.error(std::string("Descriptor \"") + getName() + + "\" has no Attribute specification!"); + valid = false; + } else { + if (attributesDescriptor->hasAttribute("name")) { + logger.error( + std::string("Descriptor \"") + getName() + + "\" has an attribute \"name\" which is a reserved word!"); + valid = false; + } + valid = valid & attributesDescriptor->validate(logger); + } + // check that only one FieldDescriptor is of type TREE. + auto fds = Descriptor::getFieldDescriptors(); + bool hasTREE = false; + for (auto fd : fds) { + if (fd->getFieldType() == FieldDescriptor::FieldType::TREE) { + if (!hasTREE) { + hasTREE = true; + } else { + logger.error( + std::string("Descriptor \"") + getName() + + "\" has multiple TREE fields, which is not permitted", + *fd); + valid = false; + break; + } + } + } + + // check attributes and the FieldDescriptors + return valid & continueValidationCheckDuplicates(fds, logger); +} + +NodeVector Descriptor::pathTo(Handle target, + Logger &logger) const +{ + bool success = false; + return ousia::pathTo(this, logger, target, success); +} + +std::pair, bool> Descriptor::pathTo( + Handle field, Logger &logger) const +{ + bool success = false; + NodeVector path = ousia::pathTo(this, logger, field, success); + return std::make_pair(path, success); +} + +NodeVector Descriptor::getDefaultFields() const +{ + // TODO: In principle a cast would be nicer here, but for now we copy. + NodeVector nodes = collect(this, [](Handle n) { + if (!n->isa(&RttiTypes::FieldDescriptor)) { + return false; + } + Handle f = n.cast(); + return f->getFieldType() == FieldDescriptor::FieldType::TREE && + f->isPrimitive(); + }); + NodeVector res; + for (auto n : nodes) { + res.push_back(n.cast()); + } + return res; +} + +NodeVector Descriptor::getPermittedChildren() const +{ + // TODO: In principle a cast would be nicer here, but for now we copy. + NodeVector nodes = collect(this, [](Handle n) { + return n->isa(&RttiTypes::StructuredClass); + }); + NodeVector res; + for (auto n : nodes) { + res.push_back(n.cast()); + } + return res; +} + +static ssize_t getFieldDescriptorIndex(const NodeVector &fds, + const std::string &name) +{ + if (fds.empty()) { + return -1; + } + + if (name == DEFAULT_FIELD_NAME) { + if (fds.back()->getFieldType() == FieldDescriptor::FieldType::TREE) { + return fds.size() - 1; + } else { + /* The last field has to be the TREE field. If the last field does + * not have the FieldType TREE no TREE-field exists at all. So we + * return -1. + */ + return -1; + } + } + + for (size_t f = 0; f < fds.size(); f++) { + if (fds[f]->getName() == name) { + return f; + } + } + return -1; +} + +ssize_t Descriptor::getFieldDescriptorIndex(const std::string &name) const +{ + NodeVector fds = getFieldDescriptors(); + return ousia::getFieldDescriptorIndex(fds, name); +} + +ssize_t Descriptor::getFieldDescriptorIndex(Handle fd) const +{ + size_t f = 0; + for (auto &fd2 : getFieldDescriptors()) { + if (fd == fd2) { + return f; + } + f++; + } + return -1; +} + +Rooted Descriptor::getFieldDescriptor( + const std::string &name) const +{ + NodeVector fds = getFieldDescriptors(); + ssize_t idx = ousia::getFieldDescriptorIndex(fds, name); + if (idx != -1) { + return fds[idx]; + } else { + return nullptr; + } +} + +bool Descriptor::addAndSortFieldDescriptor(Handle fd, + Logger &logger) +{ + // only add it if we need to. + auto fds = getFieldDescriptors(); + if (fds.find(fd) == fds.end()) { + invalidate(); + // check if the previous field is a tree field already. + if (!fieldDescriptors.empty() && + fieldDescriptors.back()->getFieldType() == + FieldDescriptor::FieldType::TREE && + fd->getFieldType() != FieldDescriptor::FieldType::TREE) { + // if so we add the new field before the TREE field. + fieldDescriptors.insert(fieldDescriptors.end() - 1, fd); + return true; + } else { + fieldDescriptors.push_back(fd); + } + } + return false; +} + +bool Descriptor::addFieldDescriptor(Handle fd, Logger &logger) +{ + if (fd->getParent() == nullptr) { + fd->setParent(this); + } + return addAndSortFieldDescriptor(fd, logger); +} + +bool Descriptor::moveFieldDescriptor(Handle fd, Logger &logger) +{ + bool sorted = addAndSortFieldDescriptor(fd, logger); + Handle par = fd->getParent(); + if (par != this) { + if (par != nullptr) { + // remove the FieldDescriptor from the old parent. + par.cast()->removeFieldDescriptor(fd); + } + fd->setParent(this); + } + return sorted; +} + +bool Descriptor::copyFieldDescriptor(Handle fd, Logger &logger) +{ + Rooted copy; + if (fd->isPrimitive()) { + copy = Rooted{new FieldDescriptor( + getManager(), fd->getPrimitiveType(), this, fd->getFieldType(), + fd->getName(), fd->isOptional())}; + } else { + /* + * In case of non-primitive FieldDescriptors we also want to copy the + * child references. + */ + copy = Rooted{ + new FieldDescriptor(getManager(), this, fd->getFieldType(), + fd->getName(), fd->isOptional())}; + for (auto c : fd->getChildren()) { + copy->addChild(c); + } + } + return addFieldDescriptor(copy, logger); +} + +bool Descriptor::removeFieldDescriptor(Handle fd) +{ + auto it = fieldDescriptors.find(fd); + if (it != fieldDescriptors.end()) { + invalidate(); + fieldDescriptors.erase(it); + fd->setParent(nullptr); + return true; + } + return false; +} + +std::pair, bool> +Descriptor::createPrimitiveFieldDescriptor(Handle primitiveType, + Logger &logger, + FieldDescriptor::FieldType fieldType, + std::string name, bool optional) +{ + Rooted fd{new FieldDescriptor(getManager(), primitiveType, + this, fieldType, + std::move(name), optional)}; + bool sorted = addFieldDescriptor(fd, logger); + return std::make_pair(fd, sorted); +} + +std::pair, bool> Descriptor::createFieldDescriptor( + Logger &logger, FieldDescriptor::FieldType fieldType, std::string name, + bool optional) +{ + Rooted fd{new FieldDescriptor( + getManager(), this, fieldType, std::move(name), optional)}; + bool sorted = addFieldDescriptor(fd, logger); + return std::make_pair(fd, sorted); +} + +/* Class StructuredClass */ + +StructuredClass::StructuredClass(Manager &mgr, std::string name, + Handle ontology, Variant cardinality, + Handle superclass, + bool transparent, bool root) + : Descriptor(mgr, std::move(name), ontology), + cardinality(cardinality), + superclass(acquire(superclass)), + subclasses(this), + transparent(transparent), + root(root) +{ + ExceptionLogger logger; + if (superclass != nullptr) { + superclass->addSubclass(this, logger); + } + if (ontology != nullptr) { + ontology->addStructuredClass(this); + } +} + +bool StructuredClass::doValidate(Logger &logger) const +{ + bool valid = true; + // check if all registered subclasses have this StructuredClass as parent. + for (Handle sub : subclasses) { + if (sub->getSuperclass() != this) { + logger.error(std::string("Struct \"") + sub->getName() + + "\" is registered as subclass of \"" + getName() + + "\" but does not have it as superclass!", + *this); + valid = false; + } + } + // check the cardinality. + if (!cardinality.isCardinality()) { + logger.error(cardinality.toString() + " is not a cardinality!", *this); + valid = false; + } + // check the validity of this superclass. + if (superclass != nullptr) { + valid = valid & superclass->validate(logger); + } + // check the validity as a Descriptor. + /* + * Note that we do not check the validity of all subclasses. This is because + * it will lead to cycles as the subclasses would call validate on their + * superclass, which is this one. + */ + return valid & Descriptor::doValidate(logger); +} + +void StructuredClass::setSuperclass(Handle sup, Logger &logger) +{ + if (superclass == sup) { + return; + } + // remove this subclass from the old superclass. + if (superclass != nullptr) { + superclass->removeSubclass(this, logger); + } + // set the new superclass + superclass = acquire(sup); + invalidate(); + // add this class as new subclass of the new superclass. + if (sup != nullptr) { + sup->addSubclass(this, logger); + // set the attribute descriptor supertype + getAttributesDescriptor()->setParentStructure( + sup->getAttributesDescriptor(), logger); + } else { + getAttributesDescriptor()->setParentStructure(nullptr, logger); + } +} + +bool StructuredClass::isSubclassOf(Handle c) const +{ + if (c == nullptr || superclass == nullptr) { + return false; + } + if (c == superclass) { + return true; + } + return superclass->isSubclassOf(c); +} + +void StructuredClass::addSubclass(Handle sc, Logger &logger) +{ + if (sc == nullptr) { + return; + } + // check if we already have that class. + if (subclasses.find(sc) == subclasses.end()) { + invalidate(); + subclasses.push_back(sc); + } + sc->setSuperclass(this, logger); +} + +void StructuredClass::removeSubclass(Handle sc, Logger &logger) +{ + // if we don't have this subclass we can return directly. + if (sc == nullptr) { + return; + } + auto it = subclasses.find(sc); + if (it == subclasses.end()) { + return; + } + // otherwise we have to erase it. + invalidate(); + subclasses.erase(it); + sc->setSuperclass(nullptr, logger); +} + +Rooted StructuredClass::gatherFieldDescriptors( + NodeVector ¤t, + std::unordered_set &visited, + std::set &overriddenFields, bool hasTREE) const +{ + // this check is to prevent cycles of inheritance to mess up this function. + if (!visited.insert(this).second) { + return nullptr; + } + Rooted mainField; + NodeVector tmp; + // first gather the non-overridden fields. + for (auto f : Descriptor::getFieldDescriptors()) { + if (overriddenFields.insert(f->getName()).second) { + bool isTREE = f->getFieldType() == FieldDescriptor::FieldType::TREE; + if (!isTREE) { + tmp.push_back(f); + } else { + if (!hasTREE) { + hasTREE = true; + mainField = f; + } + } + } + } + // append all non-overridden superclass fields. + + if (superclass != nullptr) { + Rooted super_main_field = + superclass->gatherFieldDescriptors(current, visited, + overriddenFields, hasTREE); + if (!hasTREE) { + mainField = super_main_field; + } + } + // then append all subtree fields of this level. + current.insert(current.end(), tmp.begin(), tmp.end()); + // and return the main field. + return mainField; +} + +NodeVector StructuredClass::getFieldDescriptors() const +{ + // in this case we return a NodeVector of Rooted entries without owner. + NodeVector vec; + std::unordered_set visited; + std::set overriddenFields; + Rooted mainField = + gatherFieldDescriptors(vec, visited, overriddenFields, false); + if (mainField != nullptr) { + vec.push_back(mainField); + } + return vec; +} + +/* Class AnnotationClass */ + +AnnotationClass::AnnotationClass(Manager &mgr, std::string name, + Handle ontology) + : Descriptor(mgr, std::move(name), ontology) +{ + if (ontology != nullptr) { + ontology->addAnnotationClass(this); + } +} + +/* Class Ontology */ + +void Ontology::doResolve(ResolutionState &state) +{ + continueResolveComposita(structuredClasses, structuredClasses.getIndex(), + state); + continueResolveComposita(annotationClasses, annotationClasses.getIndex(), + state); + continueResolveReferences(typesystems, state); + continueResolveReferences(ontologies, state); +} + +bool Ontology::doValidate(Logger &logger) const +{ + // check validity of name, of StructuredClasses, of AnnotationClasses and + // TypeSystems. + return validateName(logger) & + continueValidationCheckDuplicates(structuredClasses, logger) & + continueValidationCheckDuplicates(annotationClasses, logger) & + continueValidationCheckDuplicates(typesystems, logger); +} + +void Ontology::doReference(Handle node) +{ + if (node->isa(&RttiTypes::Typesystem)) { + referenceTypesystem(node.cast()); + } + if (node->isa(&RttiTypes::Ontology)) { + referenceOntology(node.cast()); + } +} + +RttiSet Ontology::doGetReferenceTypes() const +{ + return RttiSet{&RttiTypes::Ontology, &RttiTypes::Typesystem}; +} + +void Ontology::addStructuredClass(Handle s) +{ + // only add it if we need to. + if (structuredClasses.find(s) == structuredClasses.end()) { + invalidate(); + structuredClasses.push_back(s); + } + Handle par = s->getParent(); + if (par != this) { + if (par != nullptr) { + // remove the StructuredClass from the old parent. + par.cast()->removeStructuredClass(s); + } + s->setParent(this); + } +} + +bool Ontology::removeStructuredClass(Handle s) +{ + auto it = structuredClasses.find(s); + if (it != structuredClasses.end()) { + invalidate(); + structuredClasses.erase(it); + s->setParent(nullptr); + return true; + } + return false; +} + +Rooted Ontology::createStructuredClass( + std::string name, Variant cardinality, Handle superclass, + bool transparent, bool root) +{ + return Rooted{new StructuredClass( + getManager(), std::move(name), this, cardinality, superclass, + std::move(transparent), std::move(root))}; +} + +void Ontology::addAnnotationClass(Handle a) +{ + // only add it if we need to. + if (annotationClasses.find(a) == annotationClasses.end()) { + invalidate(); + annotationClasses.push_back(a); + } + Handle par = a->getParent(); + if (par != this) { + if (par != nullptr) { + // remove the StructuredClass from the old parent. + par.cast()->removeAnnotationClass(a); + } + a->setParent(this); + } +} + +bool Ontology::removeAnnotationClass(Handle a) +{ + auto it = annotationClasses.find(a); + if (it != annotationClasses.end()) { + invalidate(); + annotationClasses.erase(it); + a->setParent(nullptr); + return true; + } + return false; +} + +Rooted Ontology::createAnnotationClass(std::string name) +{ + return Rooted{ + new AnnotationClass(getManager(), std::move(name), this)}; +} + +/* Type registrations */ + +namespace RttiTypes { +const Rtti FieldDescriptor = + RttiBuilder("FieldDescriptor").parent(&Node); +const Rtti Descriptor = + RttiBuilder("Descriptor").parent(&Node); +const Rtti StructuredClass = + RttiBuilder("StructuredClass") + .parent(&Descriptor) + .composedOf(&FieldDescriptor); +const Rtti AnnotationClass = + RttiBuilder("AnnotationClass").parent(&Descriptor); +const Rtti Ontology = RttiBuilder("Ontology") + .parent(&RootNode) + .composedOf({&StructuredClass, &AnnotationClass}); +} +} \ No newline at end of file diff --git a/src/core/model/Ontology.hpp b/src/core/model/Ontology.hpp new file mode 100644 index 0000000..948caa5 --- /dev/null +++ b/src/core/model/Ontology.hpp @@ -0,0 +1,1203 @@ +/* + 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 . +*/ + +/** + * @file Ontology.hpp + * + * This header contains the class hierarchy of descriptor classes for ontologies. + * Properly connected instances of these classes with a Ontology node as root + * describe a semantic Ontology in a formal way. It specifies the allowed (tree) + * structure of a document by means of StructuredClasses as well as the allowed + * Annotations by means of AnnotationClasses. + * + * The Structure Description contained in the hierarchy of StructuredClasses is + * equivalent to a context free grammar of a special form. We introduce the + * 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 XML: + * + * \code{.xml} + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * \endcode + * + * Note that we define one field as the TREE (meaning the main or default + * document structure) and one mearly as SUBTREE, relating to supporting + * information. You are not allowed to define more than one field of type + * "TREE". + * + * The translation to a context free grammar is as follows: + * + * \code{.txt} + * 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 + * \endcode + * + * Note that this translation recurs to further nonterminals like SECTION but + * necessarily produces one "book" terminal. Also note that, in principle, + * this grammar translation allows for arbitrarily many children instances of + * 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" ontology + * to add titles to our structure. + * + * \code{.xml} + * + * + * + * + * + * + * ... + * + * + * + * \endcode + * + * This would change the context free grammar as follows: + * + * \code{.txt} + * BOOK := HEADING BOOK_TREE + * HEADING := PARAGRAPH + * \endcode + * + * AnnotationClasses on the other hand do not specify a context free grammar. + * They merely specify what kinds of Annotations are allowed within this ontology + * 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. An example for that would be the "comment" ontology: + * + * \code{.xml} + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * \endcode + * + * Here we have comment annotations, which have a reply tree as sub structure. + * + * @author Benjamin Paaßen (bpaassen@techfak.uni-bielefeld.de) + */ + +#ifndef _OUSIA_MODEL_DOMAIN_HPP_ +#define _OUSIA_MODEL_DOMAIN_HPP_ + +#include +#include + +#include "Node.hpp" +#include "RootNode.hpp" +#include "Typesystem.hpp" + +namespace ousia { + +// Forward declarations +class Rtti; +class Descriptor; +class StructuredClass; +class Ontology; + +/** + * Magic field name used to identify the default field. The default field is + * either the tree field or the only subtree field. + */ +static const std::string DEFAULT_FIELD_NAME = "$default"; + +/** + * As mentioned in the description above a FieldDescriptor specifies the + * StructuredClasses that are allowed as children of a StructuredClass or + * AnnotationClass. A field may also be primitive, which means that a proper + * instance of the respective StructuredClass or AnnotationClass must provide + * accordingly typed content without further descending in the Structure + * Hierarchy. + * + * As an example consider the "text" StructuredClass, which might allow + * the actual text content. Here is the according XML: + * + * \code{.xml} + * + * + * + * \endcode + * + */ +class FieldDescriptor : public Node { + friend Descriptor; + +public: + /** + * This enum class contains all possible FieldTypes, meaning either the + * main structure beneath this Descriptor (TREE) or supporting structure + * (SUBTREE) + * + * Note that there may be only one TREE field in a descriptor. + */ + enum class FieldType { TREE, SUBTREE }; + +private: + NodeVector children; + FieldType fieldType; + Owned primitiveType; + bool optional; + bool primitive; + +protected: + bool doValidate(Logger &logger) const override; + +public: + /** + * This is the constructor for primitive fields. + * + * @param mgr is the global Manager instance. + * @param parent is a handle of the Descriptor node that has this + * FieldDescriptor. + * @param primitiveType is a handle to some Type in some Typesystem of which + * one instance is allowed to fill this field. + * @param name is the name of this field. + * @param optional should be set to 'false' is this field needs to be + * filled in order for an instance of the parent + * Descriptor to be valid. + */ + FieldDescriptor(Manager &mgr, Handle primitiveType, + Handle parent, + FieldType fieldType = FieldType::TREE, + std::string name = "", bool optional = false); + + /** + * This is the constructor for non-primitive fields. You have to provide + * children here later on. + * + * @param mgr is the global Manager instance. + * @param parent is a handle of the Descriptor node that has this + * FieldDescriptor. + * @param fieldType is the FieldType of this FieldDescriptor, either + * TREE for the main or default structure or SUBTREE + * for supporting structures. + * @param name is the name of this field. + * @param optional should be set to 'false' is this field needs to be + * filled in order for an instance of the parent + * Descriptor to be valid. + */ + FieldDescriptor(Manager &mgr, Handle parent = nullptr, + FieldType fieldType = FieldType::TREE, + std::string name = "", bool optional = false); + + /** + * Returns a const reference to the NodeVector of StructuredClasses whose + * instances are allowed as children in the StructureTree of instances of + * this field. + * + * @return a const reference to the NodeVector of StructuredClasses whose + * instances are allowed as children in the StructureTree of instances of + * this field. + */ + const NodeVector &getChildren() const { return children; } + + /** + * Returns all StructuredClasses whose instances are allowed as children in + * the Structure Tree of instances of this field including subclasses of + * children, which are allowed directly. + * + * @return all StructuredClasses whose instances are allowed as children in + * the Structure Tree of instances of this field including subclasses of + * children, which are allowed directly. + */ + NodeVector getChildrenWithSubclasses() const; + + /** + * Adds a StructuredClass whose instances shall be allowed as children in + * the StructureTree of instances of this field. + */ + void addChild(Handle c) + { + invalidate(); + children.push_back(c); + } + + /** + * Adds multiple StructuredClasses whose instances shall be allowed as + * children in the StructureTree of instances of this field. + */ + void addChildren(const std::vector> &cs) + { + invalidate(); + children.insert(children.end(), cs.begin(), cs.end()); + } + + /** + * Removes the given StructuredClass from the list of children of this + * FieldDescriptor. + * + * @param c some StructuredClass that shan't be a child of this + * FieldDescriptor anymore. + * @return true if the FieldDescriptor contained this child and false if it + * did not. + */ + bool removeChild(Handle c); + + /** + * Returns the type of this field (not to be confused with the primitive + * type of this field). + * + * @return the type of this field. + */ + FieldType getFieldType() const { return fieldType; } + /** + * Sets the type of this field (not to be confused with the primitive type + * of this field). + * + * @param ft is the new type of this field. + */ + void setFieldType(const FieldType &ft) + { + invalidate(); + fieldType = ft; + } + + /** + * Returns if this field is primitive. + * + * @return true if and only if this field is primitive. + */ + bool isPrimitive() const { return primitive; } + + /** + * Returns the primitive type of this field, which is only allowed to be + * set if the type of this field is PRIMITIVE. + * + * @return the primitive type of this field. + */ + Rooted getPrimitiveType() const { return primitiveType; } + + /** + * Sets the primitive type of this field, which is only allowed to be + * set if the type of this field is PRIMITIVE. + * + * @param t is the new primitive type of this field- + */ + void setPrimitiveType(Handle t) + { + invalidate(); + primitiveType = acquire(t); + } + + /** + * Returns true if and only if this field is optional. + * + * @return true if and only if this field is optional. + */ + bool isOptional() const { return optional; } + + /** + * Specifies whether this field shall be optional. + * + * @param o should be true if and only if this field should be optional. + */ + void setOptional(bool o) + { + invalidate(); + optional = std::move(o); + } + + /** + * This tries to construct the shortest possible path of this Descriptor + * to the given child Descriptor. Note that this method has the problem that + * an empty return path does NOT strictly imply that no such path could + * be constructed: We also return an empty vector if the given + * Descriptor is a direct child. Therefore we also return a bool value + * indicating that the path is valid or not. + * + * Implicitly this does a breadth-first search on the graph of + * StructuredClasses that are transparent. It also takes care of cycles. + * + * @param childDescriptor is a supposedly valid child Descriptor of this + * Descriptor. + * @return a tuple containing a path of FieldDescriptors and + * StructuredClasses between this Descriptor and the + * input Descriptor and a bool value indicating if + * the construction was successful. + * + */ + std::pair, bool> pathTo( + Handle childDescriptor, Logger &logger) const; + /** + * This tries to construct the shortest possible path of this Descriptor + * to the given FieldDescriptor. Note that this method has the problem that + * an empty return path does NOT strictly imply that no such path could + * be constructed: We also return an empty vector if the given + * FieldDescriptor is a direct child. Therefore we also return a bool value + * indicating that the path is valid or not. + * + * + * Implicitly this does a breadth-first search on the graph of + * StructuredClasses that are transparent. It also takes care of cycles. + * + * @param field is a FieldDescriptor that may be allowed as child of this + * Descriptor. + * @return a path of FieldDescriptors and StructuredClasses between + * this Descriptor and the input FieldDescriptor or an empty + * vector if no such path could be constructed. + */ + NodeVector pathTo(Handle field, + Logger &logger) const; + + /** + * Returns a vector of all TREE fields that are allowed as structure tree + * children of an instance of this Descriptor. This also makes use of + * transparency. + * The list is sorted by the number of transparent elements that have to be + * constructed to arrive at the respective FieldDescriptor. + * + * @return a vector of all TREE fields that are allowed as structure tree + * children of an instance of this Descriptor. + */ + NodeVector getDefaultFields() const; +}; + +/** + * This is a super class for StructuredClasses and AnnotationClasses and is, + * in itself, not supposed to be instantiated. It defines that both, Annotations + * and StructuredEntities, may have attributes and fields. For more information + * on fields please have a look at the header documentation as well as the + * documentation of the FieldDescriptor class. + * + * Attributes are primitive content stored in a key-value fashion. Therefore + * the attribute specification of a descriptor is done by referencing an + * appropriate StructType that contains all permitted keys and value types. + * + * In XML terms the difference between primitive fields and attributes can be + * explained as the difference between node attributes and node children. + * Consider the XML + * + * \code{.xml} + * + * value + * + * \endcode + * + * key="value" inside the A-node would be an attribute, while value + * would be a primitive field. While equivalent in XML the semantics are + * different: An attribute describes indeed attributes, features of one single + * node whereas a primitive field describes the _content_ of a node. + * + */ +class Descriptor : public Node { + friend FieldDescriptor; + +private: + Owned attributesDescriptor; + NodeVector fieldDescriptors; + + bool addAndSortFieldDescriptor(Handle fd, Logger &logger); + +protected: + void doResolve(ResolutionState &state) override; + + bool doValidate(Logger &logger) const override; + +public: + Descriptor(Manager &mgr, std::string name, Handle ontology) + : Node(mgr, std::move(name), ontology), + attributesDescriptor(acquire(new StructType(mgr, "", nullptr))), + fieldDescriptors(this) + { + } + + /** + * Returns a reference to the StructType that specifies the attribute keys + * as well as value ontologies for this Descriptor. + * + * @return a reference to the StructType that specifies the attribute keys + * as well as value ontologies for this Descriptor. + */ + Rooted getAttributesDescriptor() const + { + return attributesDescriptor; + } + + /** + * Returns the NodeVector of all FieldDescriptors of this Descriptor. + * + * @return the NodeVector of all FieldDescriptors of this Descriptor. + */ + virtual NodeVector getFieldDescriptors() const + { + return fieldDescriptors; + } + + /** + * Returns the index of the FieldDescriptor with the given name or -1 if no + * such FieldDescriptor was found. + * + * @param name the name of a FieldDescriptor. + + * @return the index of the FieldDescriptor with the given name or -1 if + * no such FieldDescriptor was found. + */ + ssize_t getFieldDescriptorIndex( + const std::string &name = DEFAULT_FIELD_NAME) const; + /** + * Returns the index of the given FieldDescriptor or -1 of the given + * FieldDescriptor is not registered at this Descriptor. + * + * @param fd a FieldDescriptor. + + * @return the index of the given FieldDescriptor or -1 of the given + * FieldDescriptor is not registered at this Descriptor. + */ + ssize_t getFieldDescriptorIndex(Handle fd) const; + /** + * Returns the FieldDescriptor with the given name. + * + * @param name the name of a FieldDescriptor. + + * @return the FieldDescriptor with the given name or a nullptr if no + * such FieldDescriptor was found. + */ + Rooted getFieldDescriptor( + const std::string &name = DEFAULT_FIELD_NAME) const; + + /** + * This returns true if this Descriptor has a FieldDescriptor with the + * given name. + * + * @param name the name of a FieldDescriptor. + + * @return true if this Descriptor has a FieldDescriptor with the given + * name + */ + bool hasField(const std::string &fieldName = DEFAULT_FIELD_NAME) const + { + return getFieldDescriptorIndex(fieldName) != -1; + } + + /** + * Adds the given FieldDescriptor to this Descriptor. This also sets the + * parent of the given FieldDescriptor if it is not set yet. + * + * @param fd is a FieldDescriptor. + * @return returns true if the given FieldDescriptor was not added at the + * end one place before because a TREE field already existed and + * the TREE field has to be at the end. + */ + bool addFieldDescriptor(Handle fd, Logger &logger); + + /** + * Adds the given FieldDescriptor to this Descriptor. This also sets the + * parent of the given FieldDescriptor if it is not set to this Descriptor + * already and removes it from the old parent Descriptor. + * + * @param fd is a FieldDescriptor. + * @return returns true if the given FieldDescriptor was not added at the + * end one place before because a TREE field already existed and + * the TREE field has to be at the end. + */ + bool moveFieldDescriptor(Handle fd, Logger &logger); + + /** + * Copies a FieldDescriptor that belongs to another Descriptor to this + * Descriptor. + * + * @param fd some FieldDescriptor belonging to another Descriptor. + * @return returns true if the given FieldDescriptor was not added at the + * end one place before because a TREE field already existed and + * the TREE field has to be at the end. + */ + bool copyFieldDescriptor(Handle fd, Logger &logger); + + /** + * Removes the given FieldDescriptor from this Descriptor. This also sets + * the parent of the given FieldDescriptor to null. + * + * @param fd is a FieldDescriptor. + * @return true if the FieldDescriptor was removed and false if this + * Descriptor did not have the given FieldDescriptor as child. + */ + bool removeFieldDescriptor(Handle fd); + + /** + * This creates a new primitive FieldDescriptor and adds it to this + * Descriptor. + * + * @param primitiveType is a handle to some Type in some Typesystem of which + * one instance is allowed to fill this field. + * @param name is the name of this field. + * @param optional should be set to 'false' is this field needs to be + * filled in order for an instance of the parent + * Descriptor to be valid. + * + * @return the newly created FieldDescriptor and a bool + * indicating whether the order of FieldDescriptors had + * to be changed for the TREE field to be in the last + * spot. + */ + std::pair, bool> createPrimitiveFieldDescriptor( + Handle primitiveType, Logger &logger, + FieldDescriptor::FieldType fieldType = FieldDescriptor::FieldType::TREE, + std::string name = "", bool optional = false); + + /** + * This creates a new primitive FieldDescriptor and adds it to this + * Descriptor. + * + * @param fieldType is the FieldType of this FieldDescriptor, either + * TREE for the main or default structure or SUBTREE + * for supporting structures. + * @param name is the name of this field. + * @param optional should be set to 'false' is this field needs to be + * filled in order for an instance of the parent + * Descriptor to be valid. + * + * @return the newly created FieldDescriptor and a bool + * indicating whether the order of FieldDescriptors had + * to be changed for the TREE field to be in the last + * spot. + */ + std::pair, bool> createFieldDescriptor( + Logger &logger, + FieldDescriptor::FieldType fieldType = FieldDescriptor::FieldType::TREE, + std::string name = "", bool optional = false); + + /** + * This tries to construct the shortest possible path of this Descriptor + * to the given child Descriptor. As an example consider the book ontology + * from above. + * + * First consider the call book->pathTo(chapter). This is an easy example: + * Our path just contains a reference to the default field of book, because + * a chapter may be directly added to the main field of book. + * + * Second consider the call book->pathTo(text). This is somewhat more + * complicated, but it is still a valid request, because we can construct + * the path: {book_main_field, paragraph, paragraph_main_field}. + * This is only valid because paragraph is transparent. + * + * What about the call book->pathTo(section)? This will lead to an empty + * return path (= invalid). We could, of course, in principle construct + * a path between book and section (via chapter), but chapter is not + * transparent. Therefore that path is not allowed. + * + * Implicitly this does a breadth-first search on the graph of + * StructuredClasses that are transparent. It also takes care of cycles. + * + * @param childDescriptor is a supposedly valid child Descriptor of this + * Descriptor. + * @return either a path of FieldDescriptors and + * StructuredClasses between this Descriptor and + * the input StructuredClass or an empty vector if + * no such path can be constructed. + * + */ + NodeVector pathTo(Handle childDescriptor, + Logger &logger) const; + /** + * This tries to construct the shortest possible path of this Descriptor + * to the given FieldDescriptor. Note that this method has the problem that + * an empty return path does NOT strictly imply that no such path could + * be constructed: We also return an empty vector if the given + * FieldDescriptor is a direct child. Therefore we also return a bool value + * indicating that the path is valid or not. + * + * + * Implicitly this does a breadth-first search on the graph of + * StructuredClasses that are transparent. It also takes care of cycles. + * + * @param field is a FieldDescriptor that may be allowed as child of this + * Descriptor. + * @return returns a tuple containing a path of FieldDescriptors and + * StructuredClasses between this Descriptor and the input + * FieldDescriptor and a bool value indicating if the + * construction was successful. + */ + std::pair, bool> pathTo(Handle field, + Logger &logger) const; + + /** + * Returns a vector of all TREE fields that are allowed as structure tree + * children of an instance of this Descriptor. This also makes use of + * transparency. + * The list is sorted by the number of transparent elements that have to be + * constructed to arrive at the respective FieldDescriptor. + * + * @return a vector of all TREE fields that are allowed as structure tree + * children of an instance of this Descriptor. + */ + NodeVector getDefaultFields() const; + + /** + * Returns a vector of all StructuredClasses that are allowed as children + * of an instance of this Descriptor in the structure tree. This also makes + * use of transparency. + * The list is sorted by the number of transparent elements that have to be + * constructed to arrive at the respective FieldDescriptor. + * + * @return a vector of all StructuredClasses that are allowed as children + * of an instance of this Descriptor in the structure tree. + */ + NodeVector getPermittedChildren() const; +}; +/* + * TODO: We should discuss Cardinalities one more time. Is it smart to define + * cardinalities independent of context? Should we not have at least have the + * possibility to define it context-dependently? + */ + +/** + * A StructuredClass specifies nodes in the StructureTree of a document that + * implements this ontology. For more information on the StructureTree please + * consult the Header documentation above. + * + * Note that a StructuredClass may "invade" an existing Ontology description by + * defining itself as a viable child in one existing field. Consider the + * example of the "heading" ontology from the header documentation again: + * + * \code{.xml} + * + * + * + * + * + * + * + * + * + * + * ... + * + * + * + * + * + * + * \endcode + * + * The "parent" construct allows to "invade" another ontology. + * + * This does indeed interfere with an existing ontology and one must carefully + * craft such parent references to not create undesired side effects. However + * they provide the most convenient mechanism to extend existing ontologies + * without having to rewrite them. + * + * Another important factor is the 'transparent' flag. Transparent + * StructureClasses may be implicitly constructed in the document graph. + * If we go back to our example a user would (without transparency) have to + * explicitly declare: + * + * \code{.xml} + * + *
+ * Text. + *
+ *
+ * \endcode + * + * But in our mind the document + * + * \code{.xml} + * + *
+ * Text. + *
+ *
+ * \endcode + * + * Is already sufficiently specific. We can infer that a paragraph should be + * wrapped around "Text.". Therefore we set the 'transparent' flag of the + * "paragraph" StructuredClass to true. Please note that such inferences + * become increasingly complicated when children of transparent + * StructuredClasses are allowed to be transparent as well. So use with care. + * + * Finally we allow StructuredClasses to inherit attributes of other + * StructuredClasses. Inheritance also implies that instance of the inheriting + * class can be used wherever an instance of the inherited class is allowed. + * Inheritance therefore also goes for fields. + */ +class StructuredClass : public Descriptor { + friend Ontology; + +private: + const Variant cardinality; + Owned superclass; + NodeVector subclasses; + bool transparent; + bool root; + + /** + * Helper method for getFieldDescriptors. + */ + Rooted gatherFieldDescriptors( + NodeVector ¤t, + std::unordered_set &visited, + std::set &overriddenFields, bool hasTREE) const; + +protected: + bool doValidate(Logger &logger) const override; + +public: + /** + * The constructor for a StructuredClass. + * + * @param mgr is the current Manager. + * @param name is the name of the StructuredClass. + * @param ontology is the Ontology this StructuredClass belongs + * to. + * @param cardinality specifies how often an element of this type + * may occur at a specific point in the + * StructureTree. For example: A document should + * have at least one author. This is set to * + * per default, meaning that any number of + * of instances is valid, including zero. + * @param superclass references a parent StructuredClass. Please + * look for more information on inheritance in + * the class documentation above. The default is + * a null reference, meaning no super class. + * The constructor automatically registers this + * class as a subclass at the super class. + * @param transparent specifies whether this StructuredClass is + * transparent. For more information on + * transparency please refer to the class + * documentation above. The default is false. + * @param root specifies whether this StructuredClass is + * allowed to be at the root of a Document. + */ + StructuredClass(Manager &mgr, std::string name, + Handle ontology = nullptr, + Variant cardinality = Cardinality::any(), + Handle superclass = nullptr, + bool transparent = false, bool root = false); + + /** + * Returns the Cardinality of this StructuredClass (as a RangeSet). + * + * @return the Cardinality of this StructuredClass (as a RangeSet). + */ + const Variant &getCardinality() const { return cardinality; } + + /** + * Returns the superclass of this StructuredClass. This is not the same as + * the parents in the Structure Tree! + * + * @return the superclass of this StructuredClass. + */ + Rooted getSuperclass() const { return superclass; } + + /** + * Sets the superclass of this StructuredClass. This is not the same as + * the parents in the Structure Tree! + * + * This will also register this class as a subclass at the given superclass + * and unregister it at the previous superclass. + * + * It will also set the parent for this Descriptors AttributesDescriptor. + * + * @param sup some StructuredClass that shall be the new superclass of + * this StructuredClass. + * @param logger is some logger. Errors during setting the parent for this + * Descriptors AttributesDescriptor will be written into this + * logger. + */ + void setSuperclass(Handle sup, Logger &logger); + + /** + * Returns true if this class is a subclass of the given class. It does not + * return true if the other class is equal to the given class. + * + * @param c is another class that might or might not be a superclass of this + * one + * @return true if this class is a subclass of the given class. + * + */ + bool isSubclassOf(Handle c) const; + + /** + * Returns the StructuredClasses that are subclasses of this class. This + * is the inverted version of isa, meaning: each class c that has a isa + * relationship to this class is part of the returned vector. + * + * Note that the order of subclasses is not strictly defined. + * + * You are not allowed to add subclasses directly to the vector. When you + * construct a new StructuredClass with a non-empty isa-handle it will + * automatically register as subclass at the super class. + * + * @return the StructuredClasses that are subclasses of this class. + */ + const NodeVector &getSubclasses() const + { + return subclasses; + } + + /** + * Adds a subclass to this StructuredClass. This also calls setSuperclass + * on the given subclass. + * + * @param sc is some StructuredClass. + * @param logger is some logger. Errors during setting the parent for the + * new subclasses AttributesDescriptor will be written into + * this logger. + */ + void addSubclass(Handle sc, Logger &logger); + + /** + * Removes a subclass from this StructuredClass. This also calls + * setSuperclass(nullptr) on the given subclass. + * + * @param sc is some StructuredClass. + * @param logger is some logger. Errors during setting the parent for the + * removed subclasses AttributesDescriptor will be written + * into this logger. + */ + void removeSubclass(Handle sc, Logger &logger); + + /** + * Returns a NodeVector of all FieldDescriptors of + * this StructuredClass. This also merges the FieldDescriptors directly + * belonging to this StructuredClass with all FieldDescritptors of its + * Superclass (and so on recurvively). The order of field descriptors is + * as follows: + * 1.) non-overridden SUBTREE FieldDescriptors of super classes. + * 2.) SUBTREE FieldDescriptors of this class. + * 3.) TREE FieldDescriptor (either inherited from super class or direct) + * + * @return a NodeVector of all FieldDescriptors of this StructuredClass. + */ + NodeVector getFieldDescriptors() const override; + + bool isTransparent() const { return transparent; } + + void setTransparent(bool t) + { + invalidate(); + transparent = std::move(t); + } + + bool hasRootPermission() const { return root; } + + void setRootPermission(bool r) + { + invalidate(); + root = std::move(r); + } +}; + +/** + * An AnnotationClass defines allowed Annotations. For more information on + * Annotations please refer to the Document.hpp. + * + * This class has no special properties and is in essence just a Descriptor. + */ +class AnnotationClass : public Descriptor { + friend Ontology; + +public: + /** + * The constructor for a new AnnotationClass. Note that you have to add + * the FieldDescriptors to it later on. + * + * @param mgr is the Manager instance. + * @param name is a name for this AnnotationClass that will + * be used for later references to this + * AnnotationClass. + * @param ontology is the Ontology this AnnotationClass belongs + * to. + */ + AnnotationClass(Manager &mgr, std::string name, Handle ontology); +}; + +/** + * A Ontology node specifies which StructuredClasses and which AnnotationClasses + * are part of this ontology. TODO: Do we want to be able to restrict Annotations + * to certain Structures? + */ +class Ontology : public RootNode { + friend StructuredClass; + friend AnnotationClass; + +private: + NodeVector structuredClasses; + NodeVector annotationClasses; + NodeVector typesystems; + NodeVector ontologies; + +protected: + void doResolve(ResolutionState &state) override; + bool doValidate(Logger &logger) const override; + void doReference(Handle node) override; + RttiSet doGetReferenceTypes() const override; + +public: + /** + * The constructor for a new ontology. Note that this is an empty Ontology and + * still has to be filled with StructuredClasses and AnnotationClasses. + * + * @param mgr is the Manager instance. + * @param name is a name for this ontology which will be used for later + * references to this Ontology. + */ + Ontology(Manager &mgr, std::string name = "") + : RootNode(mgr, std::move(name), nullptr), + structuredClasses(this), + annotationClasses(this), + typesystems(this), + ontologies(this) + { + } + + /** + * The constructor for a new ontology. Note that this is an empty Ontology and + * still has to be filled with StructuredClasses and AnnotationClasses. + * + * @param mgr is the Manager instance. + * @param sys is the SystemTypesystem instance. + * @param name is a name for this ontology which will be used for later + * references to this Ontology. + */ + Ontology(Manager &mgr, Handle sys, std::string name = "") + : Ontology(mgr, std::move(name)) + { + referenceTypesystem(sys); + } + + /** + * Creates a new Ontology and returns it. + * + * @param mgr is the Manager instance. + * @param name is a name for this ontology which will be used for later + * references to this Ontology. + */ + static Rooted createEmptyOntology(Manager &mgr, std::string name) + { + return Rooted{new Ontology(mgr, std::move(name))}; + } + + /** + * Returns a const reference to the NodeVector of StructuredClasses that are + * part of this Ontology. + * + * @return a const reference to the NodeVector of StructuredClasses that are + * part of this Ontology. + */ + const NodeVector &getStructureClasses() const + { + return structuredClasses; + } + /** + * Adds a StructuredClass to this ontology. This also sets the parent of the + * given StructuredClass if it is not set to this Ontology already and removes + * it from the old Ontology. + * + * @param s is some StructuredClass. + */ + void addStructuredClass(Handle s); + + /** + * Removes a StructuredClass from this ontology. This also sets the parent of + * the given StructuredClass to null. + * + * @param s is some StructuredClass. + * @return true if the given StructuredClass was removed and false if this + * Ontology did not have the given StructuredClass as child. + */ + bool removeStructuredClass(Handle s); + + /** + * This creates a new StructuredClass and appends it to this Ontology. + * + * @param name is the name of the StructuredClass. + * @param cardinality specifies how often an element of this type + * may occur at a specific point in the + * StructureTree. For example: A document should + * have at least one author. This is set to * + * per default, meaning that any number of + * of instances is valid, including zero. + * @param superclass references a parent StructuredClass. Please + * look for more information on inheritance in + * the class documentation above. The default is + * a null reference, meaning no super class. + * The constructor automatically registers this + * class as a subclass at the super class. + * @param transparent specifies whether this StructuredClass is + * transparent. For more information on + * transparency please refer to the class + * documentation above. The default is false. + * @param root specifies whether this StructuredClass is + * allowed to be at the root of a Document. + * + * @return the newly created StructuredClass. + */ + Rooted createStructuredClass( + std::string name, Variant cardinality = Cardinality::any(), + Handle superclass = nullptr, bool transparent = false, + bool root = false); + + /** + * Returns a const reference to the NodeVector of AnnotationClasses that are + * part of this Ontology. + * + * @return a const reference to the NodeVector of AnnotationClasses that are + * part of this Ontology. + */ + const NodeVector &getAnnotationClasses() const + { + return annotationClasses; + } + /** + * Adds an AnnotationClass to this ontology. This also sets the parent of the + * given AnnotationClass if it is not set to this Ontology already and removes + * it from the old Ontology. + * + * @param a is some AnnotationClass. + */ + void addAnnotationClass(Handle a); + + /** + * Removes a AnnotationClass from this ontology. This also sets the parent of + * the given AnnotationClass to null. + * + * @param a is some AnnotationClass. + * @return true if the given AnnotationClass was removed and false if this + * Ontology did not have the given AnnotationClass as child. + */ + bool removeAnnotationClass(Handle a); + + /** + * This creates a new AnnotationClass and appends it to this Ontology. + * + * @param name is a name for this AnnotationClass that will + * be used for later references to this + * AnnotationClass. + */ + Rooted createAnnotationClass(std::string name); + + /** + * Returns a const reference to the NodeVector of TypeSystems that are + * references in this Ontology. + * + * @return a const reference to the NodeVector of TypeSystems that are + * references in this Ontology. + */ + const NodeVector &getTypesystems() const { return typesystems; } + + /** + * Adds a Typesystem reference to this Ontology. + */ + void referenceTypesystem(Handle t) { typesystems.push_back(t); } + + /** + * Adds multiple Typesystem references to this Ontology. + */ + void referenceTypesystems(const std::vector> &ts) + { + typesystems.insert(typesystems.end(), ts.begin(), ts.end()); + } + + /** + * Adds a Ontology reference to this Ontology. + */ + void referenceOntology(Handle d) { ontologies.push_back(d); } + + /** + * Adds multiple Ontology references to this Ontology. + */ + void referenceOntologys(const std::vector> &ds) + { + ontologies.insert(ontologies.end(), ds.begin(), ds.end()); + } +}; + +namespace RttiTypes { + +extern const Rtti FieldDescriptor; +extern const Rtti Descriptor; +extern const Rtti StructuredClass; +extern const Rtti AnnotationClass; +extern const Rtti Ontology; +} +} + +#endif /* _OUSIA_MODEL_DOMAIN_HPP_ */ diff --git a/src/core/model/Project.cpp b/src/core/model/Project.cpp index f7dab8a..ecc0589 100644 --- a/src/core/model/Project.cpp +++ b/src/core/model/Project.cpp @@ -18,7 +18,7 @@ #include -#include "Domain.hpp" +#include "Ontology.hpp" #include "Document.hpp" #include "Project.hpp" #include "Typesystem.hpp" @@ -69,9 +69,9 @@ Rooted Project::createDocument(const std::string &name) return document; } -Rooted Project::createDomain(const std::string &name) +Rooted Project::createOntology(const std::string &name) { - return Rooted{new Domain(getManager(), systemTypesystem, name)}; + return Rooted{new Ontology(getManager(), systemTypesystem, name)}; } void Project::referenceDocument(Handle document) diff --git a/src/core/model/Project.hpp b/src/core/model/Project.hpp index 480609c..97c711c 100644 --- a/src/core/model/Project.hpp +++ b/src/core/model/Project.hpp @@ -20,7 +20,7 @@ * @file Project.hpp * * Contains the concept of the "Project" class which represents the entity into - * which domains, documents, typesystems and other resources are embedded. + * which ontologies, documents, typesystems and other resources are embedded. * * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) */ @@ -40,12 +40,12 @@ class Registry; class SystemTypesystem; class Typesystem; class Document; -class Domain; +class Ontology; /** * The Project class constitutes the top-level node in which a collection of * documents are stored. It also contains an instance of the SystemTypesystem - * and allows for simple creation of new Typesystem and Domain instances. + * and allows for simple creation of new Typesystem and Ontology instances. */ class Project : public RootNode { private: @@ -99,12 +99,12 @@ public: Rooted createDocument(const std::string &name); /** - * Returns a new domain with the given name and adds it to the list of - * domains. Provides a reference of the system typesystem to the domain. + * Returns a new ontology with the given name and adds it to the list of + * ontologies. Provides a reference of the system typesystem to the ontology. * - * @param name is the name of the domain that should be created. + * @param name is the name of the ontology that should be created. */ - Rooted createDomain(const std::string &name); + Rooted createOntology(const std::string &name); /** * Adds the given document to the list of documents in the project. diff --git a/src/core/model/RootNode.hpp b/src/core/model/RootNode.hpp index 173a6e4..d26917f 100644 --- a/src/core/model/RootNode.hpp +++ b/src/core/model/RootNode.hpp @@ -37,7 +37,7 @@ namespace ousia { /** * The RootNode class represents a Node that may be a Root node (such as - * Documents, Typesystems and Domains). Root nodes have the property, that the + * Documents, Typesystems and Ontologys). Root nodes have the property, that the * allow importing/referencing other Nodes. */ class RootNode : public Node { diff --git a/src/core/parser/ParserScope.cpp b/src/core/parser/ParserScope.cpp index dabb03c..c46dc51 100644 --- a/src/core/parser/ParserScope.cpp +++ b/src/core/parser/ParserScope.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp index bb04bd3..2144c34 100644 --- a/src/core/parser/stack/DocumentHandler.cpp +++ b/src/core/parser/stack/DocumentHandler.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/core/parser/stack/DocumentHandler.hpp b/src/core/parser/stack/DocumentHandler.hpp index 862081c..44feb2b 100644 --- a/src/core/parser/stack/DocumentHandler.hpp +++ b/src/core/parser/stack/DocumentHandler.hpp @@ -46,7 +46,7 @@ namespace parser_stack { /** * The DocumentHandler class parses the "document" tag that is used to introduce * a new document. Note that this tag is not mandatory in osml files -- if the - * first command is not a typesystem, domain or any other declarative command, + * first command is not a typesystem, ontology or any other declarative command, * the DocumentHandler will be implicitly called. */ class DocumentHandler : public StaticHandler { diff --git a/src/core/parser/stack/DomainHandler.cpp b/src/core/parser/stack/DomainHandler.cpp deleted file mode 100644 index e86f893..0000000 --- a/src/core/parser/stack/DomainHandler.cpp +++ /dev/null @@ -1,417 +0,0 @@ -/* - 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 "DocumentHandler.hpp" -#include "DomainHandler.hpp" -#include "State.hpp" -#include "TypesystemHandler.hpp" - -namespace ousia { -namespace parser_stack { - -/* DomainHandler */ - -bool DomainHandler::start(Variant::mapType &args) -{ - // Create the Domain node - Rooted domain = - context().getProject()->createDomain(args["name"].asString()); - domain->setLocation(location()); - - // If the domain is defined inside a document, add the reference to the - // document - Rooted document = scope().select(); - if (document != nullptr) { - document->reference(domain); - } - - // Push the typesystem onto the scope, set the POST_HEAD flag to true - scope().push(domain); - scope().setFlag(ParserFlag::POST_HEAD, false); - return true; -} - -void DomainHandler::end() { scope().pop(logger()); } - -/* DomainStructHandler */ - -bool DomainStructHandler::start(Variant::mapType &args) -{ - scope().setFlag(ParserFlag::POST_HEAD, true); - - Rooted domain = scope().selectOrThrow(); - - Rooted structuredClass = domain->createStructuredClass( - args["name"].asString(), args["cardinality"].asCardinality(), nullptr, - args["transparent"].asBool(), args["isRoot"].asBool()); - structuredClass->setLocation(location()); - - const std::string &isa = args["isa"].asString(); - if (!isa.empty()) { - scope().resolve( - isa, structuredClass, logger(), - [](Handle superclass, Handle structuredClass, - Logger &logger) { - if (superclass != nullptr) { - structuredClass.cast()->setSuperclass( - superclass.cast(), logger); - } - }); - } - - scope().push(structuredClass); - return true; -} - -void DomainStructHandler::end() { scope().pop(logger()); } - -/* DomainAnnotationHandler */ -bool DomainAnnotationHandler::start(Variant::mapType &args) -{ - scope().setFlag(ParserFlag::POST_HEAD, true); - - Rooted domain = scope().selectOrThrow(); - - Rooted annotationClass = - domain->createAnnotationClass(args["name"].asString()); - annotationClass->setLocation(location()); - - scope().push(annotationClass); - return true; -} - -void DomainAnnotationHandler::end() { scope().pop(logger()); } - -/* DomainAttributesHandler */ - -bool DomainAttributesHandler::start(Variant::mapType &args) -{ - // Fetch the current typesystem and create the struct node - Rooted parent = scope().selectOrThrow(); - - Rooted attrDesc = parent->getAttributesDescriptor(); - attrDesc->setLocation(location()); - - scope().push(attrDesc); - return true; -} - -void DomainAttributesHandler::end() { scope().pop(logger()); } - -/* DomainFieldHandler */ - -bool DomainFieldHandler::start(Variant::mapType &args) -{ - FieldDescriptor::FieldType type; - if (args["isSubtree"].asBool()) { - type = FieldDescriptor::FieldType::SUBTREE; - } else { - type = FieldDescriptor::FieldType::TREE; - } - - Rooted parent = scope().selectOrThrow(); - - auto res = parent->createFieldDescriptor( - logger(), type, args["name"].asString(), args["optional"].asBool()); - res.first->setLocation(location()); - if (res.second) { - logger().warning( - std::string("Field \"") + res.first->getName() + - "\" was declared after main field. The order of fields " - "was changed to make the main field the last field.", - *res.first); - } - - scope().push(res.first); - return true; -} - -void DomainFieldHandler::end() { scope().pop(logger()); } - -/* DomainFieldRefHandler */ - -bool DomainFieldRefHandler::start(Variant::mapType &args) -{ - Rooted parent = scope().selectOrThrow(); - - const std::string &name = args["ref"].asString(); - - auto loc = location(); - - scope().resolveFieldDescriptor(name, parent, logger(), - [loc](Handle field, - Handle parent, Logger &logger) { - if (field != nullptr) { - if (parent.cast()->addFieldDescriptor( - field.cast(), logger)) { - logger.warning( - std::string("Field \"") + field->getName() + - "\" was referenced after main field was declared. The " - "order of fields was changed to make the main field " - "the last field.", - loc); - } - } - }); - return true; -} - -void DomainFieldRefHandler::end() {} - -/* DomainPrimitiveHandler */ - -bool DomainPrimitiveHandler::start(Variant::mapType &args) -{ - Rooted parent = scope().selectOrThrow(); - - FieldDescriptor::FieldType fieldType; - if (args["isSubtree"].asBool()) { - fieldType = FieldDescriptor::FieldType::SUBTREE; - } else { - fieldType = FieldDescriptor::FieldType::TREE; - } - - auto res = parent->createPrimitiveFieldDescriptor( - new UnknownType(manager()), logger(), fieldType, - args["name"].asString(), args["optional"].asBool()); - res.first->setLocation(location()); - if (res.second) { - logger().warning( - std::string("Field \"") + res.first->getName() + - "\" was declared after main field. The order of fields " - "was changed to make the main field the last field.", - *res.first); - } - - const std::string &type = args["type"].asString(); - scope().resolveType(type, res.first, logger(), - [](Handle type, Handle field, - Logger &logger) { - if (type != nullptr) { - field.cast()->setPrimitiveType(type.cast()); - } - }); - - scope().push(res.first); - return true; -} - -void DomainPrimitiveHandler::end() { scope().pop(logger()); } - -/* DomainChildHandler */ - -bool DomainChildHandler::start(Variant::mapType &args) -{ - Rooted field = scope().selectOrThrow(); - - const std::string &ref = args["ref"].asString(); - scope().resolve( - ref, field, logger(), - [](Handle child, Handle field, Logger &logger) { - if (child != nullptr) { - field.cast()->addChild( - child.cast()); - } - }); - return true; -} - -/* DomainParentHandler */ - -bool DomainParentHandler::start(Variant::mapType &args) -{ - Rooted strct = scope().selectOrThrow(); - - Rooted parent{ - new DomainParent(strct->getManager(), args["ref"].asString(), strct)}; - parent->setLocation(location()); - scope().push(parent); - return true; -} - -void DomainParentHandler::end() { scope().pop(logger()); } - -/* DomainParentFieldHandler */ - -bool DomainParentFieldHandler::start(Variant::mapType &args) -{ - Rooted parentNameNode = scope().selectOrThrow(); - FieldDescriptor::FieldType type; - if (args["isSubtree"].asBool()) { - type = FieldDescriptor::FieldType::SUBTREE; - } else { - type = FieldDescriptor::FieldType::TREE; - } - - const std::string &name = args["name"].asString(); - const bool optional = args["optional"].asBool(); - Rooted strct = - parentNameNode->getParent().cast(); - - // resolve the parent, create the declared field and add the declared - // StructuredClass as child to it. - scope().resolve( - parentNameNode->getName(), strct, logger(), - [type, name, optional](Handle parent, Handle strct, - Logger &logger) { - if (parent != nullptr) { - Rooted field = - (parent.cast()->createFieldDescriptor( - logger, type, name, optional)).first; - field->addChild(strct.cast()); - } - }); - return true; -} - -/* DomainParentFieldRefHandler */ - -bool DomainParentFieldRefHandler::start(Variant::mapType &args) -{ - Rooted parentNameNode = scope().selectOrThrow(); - - const std::string &name = args["ref"].asString(); - Rooted strct = - parentNameNode->getParent().cast(); - auto loc = location(); - - // resolve the parent, get the referenced field and add the declared - // StructuredClass as child to it. - scope().resolve( - parentNameNode->getName(), strct, logger(), - [name, loc](Handle parent, Handle strct, Logger &logger) { - if (parent != nullptr) { - Rooted field = - parent.cast()->getFieldDescriptor(name); - if (field == nullptr) { - logger.error( - std::string("Could not find referenced field ") + name, - loc); - return; - } - field->addChild(strct.cast()); - } - }); - return true; -} - -namespace States { -const State Domain = StateBuilder() - .parents({&None, &Document}) - .createdNodeType(&RttiTypes::Domain) - .elementHandler(DomainHandler::create) - .arguments({Argument::String("name")}); - -const State DomainStruct = - StateBuilder() - .parent(&Domain) - .createdNodeType(&RttiTypes::StructuredClass) - .elementHandler(DomainStructHandler::create) - .arguments({Argument::String("name"), - Argument::Cardinality("cardinality", Cardinality::any()), - Argument::Bool("isRoot", false), - Argument::Bool("transparent", false), - Argument::String("isa", "")}); - -const State DomainAnnotation = - StateBuilder() - .parent(&Domain) - .createdNodeType(&RttiTypes::AnnotationClass) - .elementHandler(DomainAnnotationHandler::create) - .arguments({Argument::String("name")}); - -const State DomainAttributes = - StateBuilder() - .parents({&DomainStruct, &DomainAnnotation}) - .createdNodeType(&RttiTypes::StructType) - .elementHandler(DomainAttributesHandler::create) - .arguments({}); - -const State DomainAttribute = - StateBuilder() - .parent(&DomainAttributes) - .elementHandler(TypesystemStructFieldHandler::create) - .arguments({Argument::String("name"), Argument::String("type"), - Argument::Any("default", Variant::fromObject(nullptr))}); - -const State DomainField = StateBuilder() - .parents({&DomainStruct, &DomainAnnotation}) - .createdNodeType(&RttiTypes::FieldDescriptor) - .elementHandler(DomainFieldHandler::create) - .arguments({Argument::String("name", ""), - Argument::Bool("isSubtree", false), - Argument::Bool("optional", false)}); - -const State DomainFieldRef = - StateBuilder() - .parents({&DomainStruct, &DomainAnnotation}) - .createdNodeType(&RttiTypes::FieldDescriptor) - .elementHandler(DomainFieldRefHandler::create) - .arguments({Argument::String("ref", DEFAULT_FIELD_NAME)}); - -const State DomainStructPrimitive = - StateBuilder() - .parents({&DomainStruct, &DomainAnnotation}) - .createdNodeType(&RttiTypes::FieldDescriptor) - .elementHandler(DomainPrimitiveHandler::create) - .arguments( - {Argument::String("name", ""), Argument::Bool("isSubtree", false), - Argument::Bool("optional", false), Argument::String("type")}); - -const State DomainStructChild = StateBuilder() - .parent(&DomainField) - .elementHandler(DomainChildHandler::create) - .arguments({Argument::String("ref")}); - -const State DomainStructParent = - StateBuilder() - .parent(&DomainStruct) - .createdNodeType(&RttiTypes::DomainParent) - .elementHandler(DomainParentHandler::create) - .arguments({Argument::String("ref")}); - -const State DomainStructParentField = - StateBuilder() - .parent(&DomainStructParent) - .createdNodeType(&RttiTypes::FieldDescriptor) - .elementHandler(DomainParentFieldHandler::create) - .arguments({Argument::String("name", ""), - Argument::Bool("isSubtree", false), - Argument::Bool("optional", false)}); - -const State DomainStructParentFieldRef = - StateBuilder() - .parent(&DomainStructParent) - .createdNodeType(&RttiTypes::FieldDescriptor) - .elementHandler(DomainParentFieldRefHandler::create) - .arguments({Argument::String("ref", DEFAULT_FIELD_NAME)}); -} -} - -namespace RttiTypes { -const Rtti DomainParent = RttiBuilder( - "DomainParent").parent(&Node); -} -} diff --git a/src/core/parser/stack/DomainHandler.hpp b/src/core/parser/stack/DomainHandler.hpp deleted file mode 100644 index 76172d6..0000000 --- a/src/core/parser/stack/DomainHandler.hpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - 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 . -*/ - -/** - * @file DomainHandler.hpp - * - * Contains the Handler classes used for parsing Domain descriptors. This - * includes the "domain" tag and all describing tags below the "domain" tag. - * - * @author Benjamin Paaßen (bpaassen@techfak.uni-bielefeld.de) - */ - -#ifndef _OUSIA_DOMAIN_HANDLER_HPP_ -#define _OUSIA_DOMAIN_HANDLER_HPP_ - -#include -#include - -#include "Handler.hpp" - -namespace ousia { - -// Forward declarations -class Rtti; - -namespace parser_stack { - -// TODO: Documentation - -class DomainHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - void end() override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainHandler{handlerData}; - } -}; - -class DomainStructHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - void end() override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainStructHandler{handlerData}; - } -}; - -class DomainAnnotationHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - void end() override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainAnnotationHandler{handlerData}; - } -}; - -class DomainAttributesHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - void end() override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainAttributesHandler{handlerData}; - } -}; - -class DomainFieldHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - void end() override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainFieldHandler{handlerData}; - } -}; - -class DomainFieldRefHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - void end() override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainFieldRefHandler{handlerData}; - } -}; - -class DomainPrimitiveHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - void end() override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainPrimitiveHandler{handlerData}; - } -}; - -class DomainChildHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainChildHandler{handlerData}; - } -}; - -class DomainParent : public Node { -public: - using Node::Node; -}; - -class DomainParentHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - void end() override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainParentHandler{handlerData}; - } -}; - -class DomainParentFieldHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainParentFieldHandler{handlerData}; - } -}; - -class DomainParentFieldRefHandler : public StaticHandler { -public: - using StaticHandler::StaticHandler; - - bool start(Variant::mapType &args) override; - - static Handler *create(const HandlerData &handlerData) - { - return new DomainParentFieldRefHandler{handlerData}; - } -}; - -namespace States { -/** - * State representing a "domain" struct. - */ -extern const State Domain; - -/** - * State representing a "struct" tag within a domain description. - */ -extern const State DomainStruct; - -/** - * State representing an "annotation" tag within a domain description. - */ -extern const State DomainAnnotation; - -/** - * State representing an "attributes" tag within a structure or annotation. - */ -extern const State DomainAttributes; - -/** - * State representing an "attribute" tag within the "attributes". - */ -extern const State DomainAttribute; - -/** - * State representing a "field" tag within a structure or annotation. - */ -extern const State DomainField; - -/** - * State representing a "fieldref" tag within a structure or annotation. - */ -extern const State DomainFieldRef; - -/** - * State representing a "primitive" tag within a structure or annotation. - */ -extern const State DomainStructPrimitive; - -/** - * State representing a "child" tag within a structure or annotation. - */ -extern const State DomainStructChild; - -/** - * State representing a "parent" tag within a structure or annotation. - */ -extern const State DomainStructParent; - -/** - * State representing a "field" tag within a "parent" tag. - */ -extern const State DomainStructParentField; - -/** - * State representing a "fieldRef" tag within a "parent" tag. - */ -extern const State DomainStructParentFieldRef; -} -} - -namespace RttiTypes { -extern const Rtti DomainParent; -} -} -#endif diff --git a/src/core/parser/stack/GenericParserStates.cpp b/src/core/parser/stack/GenericParserStates.cpp index 69a6e0e..7287524 100644 --- a/src/core/parser/stack/GenericParserStates.cpp +++ b/src/core/parser/stack/GenericParserStates.cpp @@ -17,7 +17,7 @@ */ #include "DocumentHandler.hpp" -#include "DomainHandler.hpp" +#include "OntologyHandler.hpp" #include "GenericParserStates.hpp" #include "ImportIncludeHandler.hpp" #include "TypesystemHandler.hpp" @@ -28,18 +28,18 @@ namespace parser_stack { const std::multimap GenericParserStates{ {"document", &States::Document}, {"*", &States::DocumentChild}, - {"domain", &States::Domain}, - {"struct", &States::DomainStruct}, - {"annotation", &States::DomainAnnotation}, - {"attributes", &States::DomainAttributes}, - {"attribute", &States::DomainAttribute}, - {"field", &States::DomainField}, - {"fieldRef", &States::DomainFieldRef}, - {"primitive", &States::DomainStructPrimitive}, - {"childRef", &States::DomainStructChild}, - {"parentRef", &States::DomainStructParent}, - {"field", &States::DomainStructParentField}, - {"fieldRef", &States::DomainStructParentFieldRef}, + {"ontology", &States::Ontology}, + {"struct", &States::OntologyStruct}, + {"annotation", &States::OntologyAnnotation}, + {"attributes", &States::OntologyAttributes}, + {"attribute", &States::OntologyAttribute}, + {"field", &States::OntologyField}, + {"fieldRef", &States::OntologyFieldRef}, + {"primitive", &States::OntologyStructPrimitive}, + {"childRef", &States::OntologyStructChild}, + {"parentRef", &States::OntologyStructParent}, + {"field", &States::OntologyStructParentField}, + {"fieldRef", &States::OntologyStructParentFieldRef}, {"typesystem", &States::Typesystem}, {"enum", &States::TypesystemEnum}, {"entry", &States::TypesystemEnumEntry}, diff --git a/src/core/parser/stack/ImportIncludeHandler.cpp b/src/core/parser/stack/ImportIncludeHandler.cpp index d1ea97d..a6cbaea 100644 --- a/src/core/parser/stack/ImportIncludeHandler.cpp +++ b/src/core/parser/stack/ImportIncludeHandler.cpp @@ -20,7 +20,7 @@ #include #include -#include "DomainHandler.hpp" +#include "OntologyHandler.hpp" #include "DocumentHandler.hpp" #include "ImportIncludeHandler.hpp" #include "State.hpp" @@ -38,7 +38,7 @@ void ImportHandler::doHandle(const Variant &fieldData, Variant::mapType &args) Rooted leaf = scope().getLeaf(); if (leaf == nullptr || !leaf->isa(&RttiTypes::RootNode)) { logger().error( - "Import not supported here, must be inside a document, domain " + "Import not supported here, must be inside a document, ontology " "or typesystem command.", location()); return; @@ -66,7 +66,7 @@ void IncludeHandler::doHandle(const Variant &fieldData, Variant::mapType &args) namespace States { const State Import = StateBuilder() - .parents({&Document, &Typesystem, &Domain}) + .parents({&Document, &Typesystem, &Ontology}) .elementHandler(ImportHandler::create) .arguments({Argument::String("rel", ""), Argument::String("type", ""), Argument::String("src", "")}); diff --git a/src/core/parser/stack/OntologyHandler.cpp b/src/core/parser/stack/OntologyHandler.cpp new file mode 100644 index 0000000..8c0e4d9 --- /dev/null +++ b/src/core/parser/stack/OntologyHandler.cpp @@ -0,0 +1,417 @@ +/* + 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 "DocumentHandler.hpp" +#include "OntologyHandler.hpp" +#include "State.hpp" +#include "TypesystemHandler.hpp" + +namespace ousia { +namespace parser_stack { + +/* OntologyHandler */ + +bool OntologyHandler::start(Variant::mapType &args) +{ + // Create the Ontology node + Rooted ontology = + context().getProject()->createOntology(args["name"].asString()); + ontology->setLocation(location()); + + // If the ontology is defined inside a document, add the reference to the + // document + Rooted document = scope().select(); + if (document != nullptr) { + document->reference(ontology); + } + + // Push the typesystem onto the scope, set the POST_HEAD flag to true + scope().push(ontology); + scope().setFlag(ParserFlag::POST_HEAD, false); + return true; +} + +void OntologyHandler::end() { scope().pop(logger()); } + +/* OntologyStructHandler */ + +bool OntologyStructHandler::start(Variant::mapType &args) +{ + scope().setFlag(ParserFlag::POST_HEAD, true); + + Rooted ontology = scope().selectOrThrow(); + + Rooted structuredClass = ontology->createStructuredClass( + args["name"].asString(), args["cardinality"].asCardinality(), nullptr, + args["transparent"].asBool(), args["isRoot"].asBool()); + structuredClass->setLocation(location()); + + const std::string &isa = args["isa"].asString(); + if (!isa.empty()) { + scope().resolve( + isa, structuredClass, logger(), + [](Handle superclass, Handle structuredClass, + Logger &logger) { + if (superclass != nullptr) { + structuredClass.cast()->setSuperclass( + superclass.cast(), logger); + } + }); + } + + scope().push(structuredClass); + return true; +} + +void OntologyStructHandler::end() { scope().pop(logger()); } + +/* OntologyAnnotationHandler */ +bool OntologyAnnotationHandler::start(Variant::mapType &args) +{ + scope().setFlag(ParserFlag::POST_HEAD, true); + + Rooted ontology = scope().selectOrThrow(); + + Rooted annotationClass = + ontology->createAnnotationClass(args["name"].asString()); + annotationClass->setLocation(location()); + + scope().push(annotationClass); + return true; +} + +void OntologyAnnotationHandler::end() { scope().pop(logger()); } + +/* OntologyAttributesHandler */ + +bool OntologyAttributesHandler::start(Variant::mapType &args) +{ + // Fetch the current typesystem and create the struct node + Rooted parent = scope().selectOrThrow(); + + Rooted attrDesc = parent->getAttributesDescriptor(); + attrDesc->setLocation(location()); + + scope().push(attrDesc); + return true; +} + +void OntologyAttributesHandler::end() { scope().pop(logger()); } + +/* OntologyFieldHandler */ + +bool OntologyFieldHandler::start(Variant::mapType &args) +{ + FieldDescriptor::FieldType type; + if (args["isSubtree"].asBool()) { + type = FieldDescriptor::FieldType::SUBTREE; + } else { + type = FieldDescriptor::FieldType::TREE; + } + + Rooted parent = scope().selectOrThrow(); + + auto res = parent->createFieldDescriptor( + logger(), type, args["name"].asString(), args["optional"].asBool()); + res.first->setLocation(location()); + if (res.second) { + logger().warning( + std::string("Field \"") + res.first->getName() + + "\" was declared after main field. The order of fields " + "was changed to make the main field the last field.", + *res.first); + } + + scope().push(res.first); + return true; +} + +void OntologyFieldHandler::end() { scope().pop(logger()); } + +/* OntologyFieldRefHandler */ + +bool OntologyFieldRefHandler::start(Variant::mapType &args) +{ + Rooted parent = scope().selectOrThrow(); + + const std::string &name = args["ref"].asString(); + + auto loc = location(); + + scope().resolveFieldDescriptor(name, parent, logger(), + [loc](Handle field, + Handle parent, Logger &logger) { + if (field != nullptr) { + if (parent.cast()->addFieldDescriptor( + field.cast(), logger)) { + logger.warning( + std::string("Field \"") + field->getName() + + "\" was referenced after main field was declared. The " + "order of fields was changed to make the main field " + "the last field.", + loc); + } + } + }); + return true; +} + +void OntologyFieldRefHandler::end() {} + +/* OntologyPrimitiveHandler */ + +bool OntologyPrimitiveHandler::start(Variant::mapType &args) +{ + Rooted parent = scope().selectOrThrow(); + + FieldDescriptor::FieldType fieldType; + if (args["isSubtree"].asBool()) { + fieldType = FieldDescriptor::FieldType::SUBTREE; + } else { + fieldType = FieldDescriptor::FieldType::TREE; + } + + auto res = parent->createPrimitiveFieldDescriptor( + new UnknownType(manager()), logger(), fieldType, + args["name"].asString(), args["optional"].asBool()); + res.first->setLocation(location()); + if (res.second) { + logger().warning( + std::string("Field \"") + res.first->getName() + + "\" was declared after main field. The order of fields " + "was changed to make the main field the last field.", + *res.first); + } + + const std::string &type = args["type"].asString(); + scope().resolveType(type, res.first, logger(), + [](Handle type, Handle field, + Logger &logger) { + if (type != nullptr) { + field.cast()->setPrimitiveType(type.cast()); + } + }); + + scope().push(res.first); + return true; +} + +void OntologyPrimitiveHandler::end() { scope().pop(logger()); } + +/* OntologyChildHandler */ + +bool OntologyChildHandler::start(Variant::mapType &args) +{ + Rooted field = scope().selectOrThrow(); + + const std::string &ref = args["ref"].asString(); + scope().resolve( + ref, field, logger(), + [](Handle child, Handle field, Logger &logger) { + if (child != nullptr) { + field.cast()->addChild( + child.cast()); + } + }); + return true; +} + +/* OntologyParentHandler */ + +bool OntologyParentHandler::start(Variant::mapType &args) +{ + Rooted strct = scope().selectOrThrow(); + + Rooted parent{ + new OntologyParent(strct->getManager(), args["ref"].asString(), strct)}; + parent->setLocation(location()); + scope().push(parent); + return true; +} + +void OntologyParentHandler::end() { scope().pop(logger()); } + +/* OntologyParentFieldHandler */ + +bool OntologyParentFieldHandler::start(Variant::mapType &args) +{ + Rooted parentNameNode = scope().selectOrThrow(); + FieldDescriptor::FieldType type; + if (args["isSubtree"].asBool()) { + type = FieldDescriptor::FieldType::SUBTREE; + } else { + type = FieldDescriptor::FieldType::TREE; + } + + const std::string &name = args["name"].asString(); + const bool optional = args["optional"].asBool(); + Rooted strct = + parentNameNode->getParent().cast(); + + // resolve the parent, create the declared field and add the declared + // StructuredClass as child to it. + scope().resolve( + parentNameNode->getName(), strct, logger(), + [type, name, optional](Handle parent, Handle strct, + Logger &logger) { + if (parent != nullptr) { + Rooted field = + (parent.cast()->createFieldDescriptor( + logger, type, name, optional)).first; + field->addChild(strct.cast()); + } + }); + return true; +} + +/* OntologyParentFieldRefHandler */ + +bool OntologyParentFieldRefHandler::start(Variant::mapType &args) +{ + Rooted parentNameNode = scope().selectOrThrow(); + + const std::string &name = args["ref"].asString(); + Rooted strct = + parentNameNode->getParent().cast(); + auto loc = location(); + + // resolve the parent, get the referenced field and add the declared + // StructuredClass as child to it. + scope().resolve( + parentNameNode->getName(), strct, logger(), + [name, loc](Handle parent, Handle strct, Logger &logger) { + if (parent != nullptr) { + Rooted field = + parent.cast()->getFieldDescriptor(name); + if (field == nullptr) { + logger.error( + std::string("Could not find referenced field ") + name, + loc); + return; + } + field->addChild(strct.cast()); + } + }); + return true; +} + +namespace States { +const State Ontology = StateBuilder() + .parents({&None, &Document}) + .createdNodeType(&RttiTypes::Ontology) + .elementHandler(OntologyHandler::create) + .arguments({Argument::String("name")}); + +const State OntologyStruct = + StateBuilder() + .parent(&Ontology) + .createdNodeType(&RttiTypes::StructuredClass) + .elementHandler(OntologyStructHandler::create) + .arguments({Argument::String("name"), + Argument::Cardinality("cardinality", Cardinality::any()), + Argument::Bool("isRoot", false), + Argument::Bool("transparent", false), + Argument::String("isa", "")}); + +const State OntologyAnnotation = + StateBuilder() + .parent(&Ontology) + .createdNodeType(&RttiTypes::AnnotationClass) + .elementHandler(OntologyAnnotationHandler::create) + .arguments({Argument::String("name")}); + +const State OntologyAttributes = + StateBuilder() + .parents({&OntologyStruct, &OntologyAnnotation}) + .createdNodeType(&RttiTypes::StructType) + .elementHandler(OntologyAttributesHandler::create) + .arguments({}); + +const State OntologyAttribute = + StateBuilder() + .parent(&OntologyAttributes) + .elementHandler(TypesystemStructFieldHandler::create) + .arguments({Argument::String("name"), Argument::String("type"), + Argument::Any("default", Variant::fromObject(nullptr))}); + +const State OntologyField = StateBuilder() + .parents({&OntologyStruct, &OntologyAnnotation}) + .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(OntologyFieldHandler::create) + .arguments({Argument::String("name", ""), + Argument::Bool("isSubtree", false), + Argument::Bool("optional", false)}); + +const State OntologyFieldRef = + StateBuilder() + .parents({&OntologyStruct, &OntologyAnnotation}) + .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(OntologyFieldRefHandler::create) + .arguments({Argument::String("ref", DEFAULT_FIELD_NAME)}); + +const State OntologyStructPrimitive = + StateBuilder() + .parents({&OntologyStruct, &OntologyAnnotation}) + .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(OntologyPrimitiveHandler::create) + .arguments( + {Argument::String("name", ""), Argument::Bool("isSubtree", false), + Argument::Bool("optional", false), Argument::String("type")}); + +const State OntologyStructChild = StateBuilder() + .parent(&OntologyField) + .elementHandler(OntologyChildHandler::create) + .arguments({Argument::String("ref")}); + +const State OntologyStructParent = + StateBuilder() + .parent(&OntologyStruct) + .createdNodeType(&RttiTypes::OntologyParent) + .elementHandler(OntologyParentHandler::create) + .arguments({Argument::String("ref")}); + +const State OntologyStructParentField = + StateBuilder() + .parent(&OntologyStructParent) + .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(OntologyParentFieldHandler::create) + .arguments({Argument::String("name", ""), + Argument::Bool("isSubtree", false), + Argument::Bool("optional", false)}); + +const State OntologyStructParentFieldRef = + StateBuilder() + .parent(&OntologyStructParent) + .createdNodeType(&RttiTypes::FieldDescriptor) + .elementHandler(OntologyParentFieldRefHandler::create) + .arguments({Argument::String("ref", DEFAULT_FIELD_NAME)}); +} +} + +namespace RttiTypes { +const Rtti OntologyParent = RttiBuilder( + "OntologyParent").parent(&Node); +} +} diff --git a/src/core/parser/stack/OntologyHandler.hpp b/src/core/parser/stack/OntologyHandler.hpp new file mode 100644 index 0000000..caeacc7 --- /dev/null +++ b/src/core/parser/stack/OntologyHandler.hpp @@ -0,0 +1,257 @@ +/* + 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 . +*/ + +/** + * @file OntologyHandler.hpp + * + * Contains the Handler classes used for parsing Ontology descriptors. This + * includes the "ontology" tag and all describing tags below the "ontology" tag. + * + * @author Benjamin Paaßen (bpaassen@techfak.uni-bielefeld.de) + */ + +#ifndef _OUSIA_DOMAIN_HANDLER_HPP_ +#define _OUSIA_DOMAIN_HANDLER_HPP_ + +#include +#include + +#include "Handler.hpp" + +namespace ousia { + +// Forward declarations +class Rtti; + +namespace parser_stack { + +// TODO: Documentation + +class OntologyHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + void end() override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyHandler{handlerData}; + } +}; + +class OntologyStructHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + void end() override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyStructHandler{handlerData}; + } +}; + +class OntologyAnnotationHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + void end() override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyAnnotationHandler{handlerData}; + } +}; + +class OntologyAttributesHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + void end() override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyAttributesHandler{handlerData}; + } +}; + +class OntologyFieldHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + void end() override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyFieldHandler{handlerData}; + } +}; + +class OntologyFieldRefHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + void end() override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyFieldRefHandler{handlerData}; + } +}; + +class OntologyPrimitiveHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + void end() override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyPrimitiveHandler{handlerData}; + } +}; + +class OntologyChildHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyChildHandler{handlerData}; + } +}; + +class OntologyParent : public Node { +public: + using Node::Node; +}; + +class OntologyParentHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + void end() override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyParentHandler{handlerData}; + } +}; + +class OntologyParentFieldHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyParentFieldHandler{handlerData}; + } +}; + +class OntologyParentFieldRefHandler : public StaticHandler { +public: + using StaticHandler::StaticHandler; + + bool start(Variant::mapType &args) override; + + static Handler *create(const HandlerData &handlerData) + { + return new OntologyParentFieldRefHandler{handlerData}; + } +}; + +namespace States { +/** + * State representing a "ontology" struct. + */ +extern const State Ontology; + +/** + * State representing a "struct" tag within a ontology description. + */ +extern const State OntologyStruct; + +/** + * State representing an "annotation" tag within a ontology description. + */ +extern const State OntologyAnnotation; + +/** + * State representing an "attributes" tag within a structure or annotation. + */ +extern const State OntologyAttributes; + +/** + * State representing an "attribute" tag within the "attributes". + */ +extern const State OntologyAttribute; + +/** + * State representing a "field" tag within a structure or annotation. + */ +extern const State OntologyField; + +/** + * State representing a "fieldref" tag within a structure or annotation. + */ +extern const State OntologyFieldRef; + +/** + * State representing a "primitive" tag within a structure or annotation. + */ +extern const State OntologyStructPrimitive; + +/** + * State representing a "child" tag within a structure or annotation. + */ +extern const State OntologyStructChild; + +/** + * State representing a "parent" tag within a structure or annotation. + */ +extern const State OntologyStructParent; + +/** + * State representing a "field" tag within a "parent" tag. + */ +extern const State OntologyStructParentField; + +/** + * State representing a "fieldRef" tag within a "parent" tag. + */ +extern const State OntologyStructParentFieldRef; +} +} + +namespace RttiTypes { +extern const Rtti OntologyParent; +} +} +#endif diff --git a/src/core/parser/stack/TypesystemHandler.cpp b/src/core/parser/stack/TypesystemHandler.cpp index de8ee49..b62f684 100644 --- a/src/core/parser/stack/TypesystemHandler.cpp +++ b/src/core/parser/stack/TypesystemHandler.cpp @@ -17,13 +17,13 @@ */ #include -#include +#include #include #include #include #include "DocumentHandler.hpp" -#include "DomainHandler.hpp" +#include "OntologyHandler.hpp" #include "State.hpp" #include "TypesystemHandler.hpp" @@ -39,12 +39,12 @@ bool TypesystemHandler::start(Variant::mapType &args) context().getProject()->createTypesystem(args["name"].asString()); typesystem->setLocation(location()); - // If the typesystem is defined inside a domain, add a reference to the - // typesystem to the domain -- do the same with a document, if no domain + // If the typesystem is defined inside a ontology, add a reference to the + // typesystem to the ontology -- do the same with a document, if no ontology // is found - Rooted domain = scope().select(); - if (domain != nullptr) { - domain->reference(typesystem); + Rooted ontology = scope().select(); + if (ontology != nullptr) { + ontology->reference(typesystem); } else { Rooted document = scope().select(); if (document != nullptr) { @@ -190,7 +190,7 @@ bool TypesystemConstantHandler::start(Variant::mapType &args) namespace States { const State Typesystem = StateBuilder() - .parents({&None, &Domain, &Document}) + .parents({&None, &Ontology, &Document}) .createdNodeType(&RttiTypes::Typesystem) .elementHandler(TypesystemHandler::create) .arguments({Argument::String("name", "")}); diff --git a/src/core/resource/Resource.cpp b/src/core/resource/Resource.cpp index 4b9e496..7bcaf88 100644 --- a/src/core/resource/Resource.cpp +++ b/src/core/resource/Resource.cpp @@ -42,7 +42,7 @@ static std::unordered_map reverseMap static const std::unordered_map NAME_RESOURCE_TYPE_MAP{{"document", ResourceType::DOCUMENT}, - {"domain", ResourceType::DOMAIN_DESC}, + {"ontology", ResourceType::ONTOLOGY}, {"typesystem", ResourceType::TYPESYSTEM}, {"attributes", ResourceType::ATTRIBUTES}, {"stylesheet", ResourceType::STYLESHEET}, diff --git a/src/core/resource/Resource.hpp b/src/core/resource/Resource.hpp index 63ed591..548a255 100644 --- a/src/core/resource/Resource.hpp +++ b/src/core/resource/Resource.hpp @@ -48,9 +48,9 @@ enum class ResourceType { UNKNOWN, /** - * The resource contains a domain description. + * The resource contains a ontology description. */ - DOMAIN_DESC, + ONTOLOGY, /** * The resource contains a typesystem description. diff --git a/src/core/resource/ResourceRequest.cpp b/src/core/resource/ResourceRequest.cpp index f01a324..3c01e6a 100644 --- a/src/core/resource/ResourceRequest.cpp +++ b/src/core/resource/ResourceRequest.cpp @@ -33,7 +33,7 @@ namespace ousia { namespace RttiTypes { extern const Rtti Document; -extern const Rtti Domain; +extern const Rtti Ontology; extern const Rtti Node; extern const Rtti Typesystem; } @@ -43,7 +43,7 @@ extern const Rtti Typesystem; */ static const std::unordered_map RTTI_RESOURCE_TYPE_MAP{{&RttiTypes::Document, ResourceType::DOCUMENT}, - {&RttiTypes::Domain, ResourceType::DOMAIN_DESC}, + {&RttiTypes::Ontology, ResourceType::ONTOLOGY}, {&RttiTypes::Typesystem, ResourceType::TYPESYSTEM}}; /** -- cgit v1.2.3