From 4ee3c4042d267c010babb2ab86e15a6b31950849 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Tue, 3 Mar 2015 18:23:15 +0100 Subject: added a method to find the matching start anchor for some end anchor. --- src/core/model/Document.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++- src/core/model/Document.hpp | 41 +++++++++++++--- 2 files changed, 147 insertions(+), 8 deletions(-) (limited to 'src/core/model') 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 DocumentEntity::createChildAnchor(const size_t &fieldIdx) return Rooted{new Anchor(subInst->getManager(), subInst, fieldIdx)}; } +static bool matchStartAnchor(Handle desc, + const std::string &name, Handle a) +{ + return (a->getAnnotation() != nullptr) && + (a->getAnnotation()->getEnd() == nullptr) && + (desc == nullptr || a->getAnnotation()->getDescriptor() == desc) && + (name.empty() || a->getAnnotation()->getName() == name); +} + +template +Rooted DocumentEntity::searchStartAnchorInField( + Handle desc, const std::string &name, Iterator begin, + Iterator end) +{ + for (Iterator it = begin; it != end; it++) { + Handle strct = *it; + if (strct->isa(&RttiTypes::Anchor)) { + // check if this Anchor is the right one. + Handle a = strct.cast(); + if (matchStartAnchor(desc, name, a)) { + return a; + } + continue; + } else if (strct->isa(&RttiTypes::StructuredEntity)) { + // search downwards. + Rooted a = + strct.cast()->searchStartAnchorDownwards( + desc, name); + if (a != nullptr) { + return a; + } + } + } + return nullptr; +} + +Rooted DocumentEntity::searchStartAnchorDownwards( + Handle desc, const std::string &name) +{ + if (fields.empty()) { + return nullptr; + } + // get the default field. + NodeVector children = fields[fields.size() - 1]; + // search it from back to front. + return searchStartAnchorInField(desc, name, children.rbegin(), + children.rend()); +} + +Rooted DocumentEntity::searchStartAnchorUpwards( + Handle desc, const std::string &name, + const DocumentEntity *child) +{ + if (fields.empty()) { + return nullptr; + } + // get the default field. + NodeVector children = fields[fields.size() - 1]; + // search for the child from back to front. + auto it = children.rbegin(); + while (static_cast(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 DocumentEntity::searchStartAnchor(size_t fieldIdx, + Handle desc, + const std::string &name) +{ + // get the correct field. + NodeVector children = fields[fieldIdx]; + // search it from back to front. + Rooted 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() + ->searchStartAnchorUpwards(desc, name, this); + } + if (subInst->getParent()->isa(&RttiTypes::AnnotationEntity)) { + subInst->getParent().cast()->searchStartAnchorUpwards( + desc, name, this); + } + return nullptr; +} + /* Class StructureNode */ bool StructureNode::doValidate(Logger &logger) const @@ -702,7 +808,9 @@ void AnnotationEntity::setStart(Handle s) } invalidate(); start = acquire(s); - s->setAnnotation(this, true); + if (s != nullptr) { + s->setAnnotation(this, true); + } } void AnnotationEntity::setEnd(Handle e) @@ -712,7 +820,9 @@ void AnnotationEntity::setEnd(Handle 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 + Rooted searchStartAnchorInField(Handle desc, + const std::string &name, + Iterator begin, Iterator end); + + Rooted searchStartAnchorDownwards(Handle desc, + const std::string &name); + + Rooted searchStartAnchorUpwards(Handle desc, + const std::string &name, + const DocumentEntity *child); + protected: bool doValidate(Logger &logger) const; @@ -420,7 +432,7 @@ public: Rooted createChildStructuredEntity( Handle 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 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 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 searchStartAnchor(size_t fieldIdx, + Handle 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_ */ -- cgit v1.2.3