diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/model/Document.cpp | 114 | ||||
-rw-r--r-- | src/core/model/Document.hpp | 41 |
2 files changed, 147 insertions, 8 deletions
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index b29767e..62dad11 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -452,6 +452,112 @@ Rooted<Anchor> DocumentEntity::createChildAnchor(const size_t &fieldIdx) return Rooted<Anchor>{new Anchor(subInst->getManager(), subInst, fieldIdx)}; } +static bool matchStartAnchor(Handle<AnnotationClass> desc, + const std::string &name, Handle<Anchor> a) +{ + return (a->getAnnotation() != nullptr) && + (a->getAnnotation()->getEnd() == nullptr) && + (desc == nullptr || a->getAnnotation()->getDescriptor() == desc) && + (name.empty() || a->getAnnotation()->getName() == name); +} + +template <typename Iterator> +Rooted<Anchor> DocumentEntity::searchStartAnchorInField( + Handle<AnnotationClass> desc, const std::string &name, Iterator begin, + Iterator end) +{ + for (Iterator it = begin; it != end; it++) { + Handle<StructureNode> strct = *it; + if (strct->isa(&RttiTypes::Anchor)) { + // check if this Anchor is the right one. + Handle<Anchor> a = strct.cast<Anchor>(); + if (matchStartAnchor(desc, name, a)) { + return a; + } + continue; + } else if (strct->isa(&RttiTypes::StructuredEntity)) { + // search downwards. + Rooted<Anchor> a = + strct.cast<StructuredEntity>()->searchStartAnchorDownwards( + desc, name); + if (a != nullptr) { + return a; + } + } + } + return nullptr; +} + +Rooted<Anchor> DocumentEntity::searchStartAnchorDownwards( + Handle<AnnotationClass> desc, const std::string &name) +{ + if (fields.empty()) { + return nullptr; + } + // get the default field. + NodeVector<StructureNode> children = fields[fields.size() - 1]; + // search it from back to front. + return searchStartAnchorInField(desc, name, children.rbegin(), + children.rend()); +} + +Rooted<Anchor> DocumentEntity::searchStartAnchorUpwards( + Handle<AnnotationClass> desc, const std::string &name, + const DocumentEntity *child) +{ + if (fields.empty()) { + return nullptr; + } + // get the default field. + NodeVector<StructureNode> children = fields[fields.size() - 1]; + // search for the child from back to front. + auto it = children.rbegin(); + while (static_cast<void *>(it->get()) != child->subInst.get() && + it != children.rend()) { + it++; + } + // increment the reverse iterator once more to prevent downwards search + // to the child. + if (it != children.rend()) { + it++; + return searchStartAnchorInField(desc, name, it, children.rend()); + } + throw OusiaException("Internal error: Child node not found in parent!"); +} + +Rooted<Anchor> DocumentEntity::searchStartAnchor(size_t fieldIdx, + Handle<AnnotationClass> desc, + const std::string &name) +{ + // get the correct field. + NodeVector<StructureNode> children = fields[fieldIdx]; + // search it from back to front. + Rooted<Anchor> a = searchStartAnchorInField(desc, name, children.rbegin(), + children.rend()); + // if we found the Anchor, return it. + if (a != nullptr) { + return a; + } + + // If this is either an AnnotationEntity or a SUBTREE field we can not + // search upwards. + if (subInst->isa(&RttiTypes::AnnotationEntity) || + fieldIdx + 1 < fields.size()) { + return nullptr; + } + // if the children here did not contain the right start Anchor go upwards. + if (subInst->getParent()->isa(&RttiTypes::StructuredEntity)) { + return subInst->getParent() + .cast<StructuredEntity>() + ->searchStartAnchorUpwards(desc, name, this); + } + if (subInst->getParent()->isa(&RttiTypes::AnnotationEntity)) { + subInst->getParent().cast<AnnotationEntity>()->searchStartAnchorUpwards( + desc, name, this); + } + return nullptr; +} + /* Class StructureNode */ bool StructureNode::doValidate(Logger &logger) const @@ -702,7 +808,9 @@ void AnnotationEntity::setStart(Handle<Anchor> s) } invalidate(); start = acquire(s); - s->setAnnotation(this, true); + if (s != nullptr) { + s->setAnnotation(this, true); + } } void AnnotationEntity::setEnd(Handle<Anchor> e) @@ -712,7 +820,9 @@ void AnnotationEntity::setEnd(Handle<Anchor> e) } invalidate(); end = acquire(e); - e->setAnnotation(this, false); + if (e != nullptr) { + e->setAnnotation(this, false); + } } /* Class Document */ diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index dc0f73f..81e2f41 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -26,8 +26,8 @@ * * 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" ontology. That root node in turn has - * structure nodes as children, which in turn may have children. This + * 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). @@ -142,7 +142,7 @@ class Anchor; */ class DocumentEntity { private: - /* + /** * this is a rather dirty method that should not be used in other cases: * We store a handle to the Node instance that inherits from * DocumentEntity. This Handle is not registered and would lead to Segfaults @@ -156,6 +156,18 @@ private: void invalidateSubInstance(); + template <typename Iterator> + Rooted<Anchor> searchStartAnchorInField(Handle<AnnotationClass> desc, + const std::string &name, + Iterator begin, Iterator end); + + Rooted<Anchor> searchStartAnchorDownwards(Handle<AnnotationClass> desc, + const std::string &name); + + Rooted<Anchor> searchStartAnchorUpwards(Handle<AnnotationClass> desc, + const std::string &name, + const DocumentEntity *child); + protected: bool doValidate(Logger &logger) const; @@ -420,7 +432,7 @@ public: Rooted<StructuredEntity> createChildStructuredEntity( Handle<StructuredClass> descriptor, const size_t &fieldIdx, Variant attributes = Variant::mapType{}, std::string name = ""); - /* + /** * Creates a new DocumentPrimitive as child of this DocumentEntity. * * @param content is a Variant containing the content of this @@ -434,7 +446,7 @@ public: */ Rooted<DocumentPrimitive> createChildDocumentPrimitive( Variant content, const std::string &fieldName = DEFAULT_FIELD_NAME); - /* + /** * Creates a new DocumentPrimitive as child of this DocumentEntity. * * @param fieldIdx is the index of the field, where the newly created @@ -469,6 +481,23 @@ public: * @return the newly created Anchor. */ Rooted<Anchor> createChildAnchor(const size_t &fieldIdx); + + /** + * Does an inverse depth first search starting at this DocumentEntity to + * find a child Anchor element that matches the given seach criteria. + * The search will not cross SUBTREE to TREE field boundaries and will not + * leave AnnotationEntities upwards. If no Anchor is found a nullptr is + * returned. AnnotationEntities which already have an end Anchor won't be + * returned. + * + * @param desc is the AnnotationClass of the AnnotationEntity whose + * start Anchor you are looking for. + * @param name is the AnnotationEntities name. + * @return the start Anchor or a nullptr if no Anchor could be found. + */ + Rooted<Anchor> searchStartAnchor(size_t fieldIdx, + Handle<AnnotationClass> desc = nullptr, + const std::string &name = ""); }; /** @@ -1061,4 +1090,4 @@ extern const Rtti Anchor; } } -#endif /* _OUSIA_MODEL_DOCUMENT_HPP_ */
\ No newline at end of file +#endif /* _OUSIA_MODEL_DOCUMENT_HPP_ */ |