summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/model/Document.cpp114
-rw-r--r--src/core/model/Document.hpp41
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_ */