summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/model/Document.hpp4
-rw-r--r--src/core/model/Domain.cpp91
-rw-r--r--src/core/model/Domain.hpp39
-rw-r--r--test/core/model/DomainTest.cpp29
4 files changed, 89 insertions, 74 deletions
diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp
index 2821e8c..357b752 100644
--- a/src/core/model/Document.hpp
+++ b/src/core/model/Document.hpp
@@ -379,14 +379,18 @@ public:
* the markups "emphasized" and "strong". In HTML like markup languages these
* concepts are handeled as structure elements, like this:
*
+ * \code{.xml}
* <em>emphasized</em> <em><strong>and</strong></em> <strong>strong</strong>
+ * \endcode
*
* which is neither intuitive nor semantically sound. Therefore we take the
* approach of anchoring the Annotation entities in the text like this:
*
+ * \code{.xml}
* <Anchor id=1/>emphasized <Anchor id=2/>and<Anchor id=3/> strong<Anchor id=4/>
* <AnnotationEntity class="emphasized" start=1 end=3/>
* <AnnotationEntity class="strong" start=2 end=4/>
+ * \endcode
*
* Which signifies that indeed the text "emphasized and" is emphasized, not
* the two text exerpts "emphasized" and "and" separately.
diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp
index 1fb057e..d664809 100644
--- a/src/core/model/Domain.cpp
+++ b/src/core/model/Domain.cpp
@@ -47,7 +47,7 @@ std::vector<Rooted<Node>> Descriptor::pathTo(
return path;
}
-static bool pathEquals(const Descriptor& a, const Descriptor& b)
+static bool pathEquals(const Descriptor &a, const Descriptor &b)
{
// We assume that two Descriptors are equal if their names and domain names
// are equal.
@@ -59,57 +59,68 @@ static bool pathEquals(const Descriptor& a, const Descriptor& b)
return aDom->getName() == bDom->getName();
}
-//TODO: isa-handling.
bool Descriptor::continuePath(Handle<StructuredClass> target,
std::vector<Rooted<Node>> &path) const
{
- // look if our current node is reachable using the parent references
- for (auto &pfd : target->getParents()) {
- Handle<Descriptor> p = pfd->getParent().cast<Descriptor>();
- if (pathEquals(*this, *p)) {
- // if we have made the connection, stop the search.
- path.push_back(pfd);
- return true;
- }
- // look for transparent intermediate nodes.
- if (!p->isa(RttiTypes::StructuredClass)) {
- continue;
- }
- Handle<StructuredClass> pc = p.cast<StructuredClass>();
- if (pc->transparent) {
- // recursion
- std::vector<Rooted<Node>> cPath = path;
- if (continuePath(pc, cPath)) {
- path = std::move(cPath);
- path.push_back(pc);
- path.push_back(pfd);
- return true;
- }
- }
- }
+ bool found = false;
// use recursive depth-first search from the top to reach the given child
- for (auto &fd : fieldDescriptors) {
- for (auto &c : fd->getChildren()) {
- if (pathEquals(*c, *target)) {
- // if we have made the connection, stop the search.
- path.push_back(fd);
- return true;
+ if (fieldDescriptors.size() > 0) {
+ for (auto &fd : fieldDescriptors) {
+ for (auto &c : fd->getChildren()) {
+ if (pathEquals(*c, *target)) {
+ // if we have made the connection, stop the search.
+ path.push_back(fd);
+ return true;
+ }
+ // look for transparent intermediate nodes.
+ if (c->transparent) {
+ // copy the path.
+ std::vector<Rooted<Node>> cPath = path;
+ cPath.push_back(fd);
+ cPath.push_back(c);
+ // recursion.
+ if (c->continuePath(target, cPath) &&
+ (!found || path.size() > cPath.size())) {
+ // look if this path is better than the current optimum.
+ path = std::move(cPath);
+ found = true;
+ }
+ }
}
- // look for transparent intermediate nodes.
- if (c->transparent) {
+ }
+ } else {
+ // if this is a StructuredClass and if it did not formulate own
+ // fieldDescriptors (overriding the parent), we can also use the
+ // (inheritance-wise) parent
+ if (isa(RttiTypes::StructuredClass)) {
+ const StructuredClass *tis =
+ static_cast<const StructuredClass *>(this);
+ if (!tis->getIsA().isNull()) {
// copy the path.
std::vector<Rooted<Node>> cPath = path;
- cPath.push_back(fd);
- cPath.push_back(c);
- // recursion.
- if (c->continuePath(target, cPath)) {
+ if (tis->getIsA()->continuePath(target, cPath) &&
+ (found || path.size() > cPath.size())) {
+ // look if this path is better than the current optimum.
path = std::move(cPath);
- return true;
+ found = true;
}
}
}
}
- return false;
+ // either way we can try to find the targets parent (inheritance-wise)
+ // instead of the target itself.
+ if (!target->getIsA().isNull()) {
+ // copy the path.
+ std::vector<Rooted<Node>> cPath = path;
+ if (continuePath(target->getIsA(), cPath) &&
+ (!found || path.size() > cPath.size())) {
+ // look if this path is better than the current optimum.
+ path = std::move(cPath);
+ found = true;
+ }
+ }
+ // return if we found something.
+ return found;
}
/* Class Domain */
diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp
index 755ff52..1f65242 100644
--- a/src/core/model/Domain.hpp
+++ b/src/core/model/Domain.hpp
@@ -233,7 +233,7 @@ class Domain;
* As an example consider the "paragraph" StructuredClass, which might allow
* the actual text content. Here is the according XML:
*
- * \code{*.xml}
+ * \code{.xml}
* <struct name="paragraph" transparent="true" role="paragraph">
* <fields>
* <field>
@@ -376,7 +376,7 @@ public:
* explained as the difference between node attributes and node children.
* Consider the XML
*
- * \code{*.xml}
+ * \code{.xml}
* <A key="value">
* <key>value</key>
* </A>
@@ -490,7 +490,7 @@ typedef RangeSet<size_t> Cardinality;
* defining itself as a viable child in one existing field. Consider the
* example of the "heading" domain from the header documentation again:
*
- * \code{*.xml}
+ * \code{.xml}
* <domain name="headings">
* <head>
* <import rel="domain" src="book.oxm"/>
@@ -522,7 +522,7 @@ typedef RangeSet<size_t> Cardinality;
* If we go back to our example a user would (without transparency) have to
* explicitly declare:
*
- * \code{*.xml}
+ * \code{.xml}
* <book>
* <section>
* <paragraph>Text.</paragraph>
@@ -532,7 +532,7 @@ typedef RangeSet<size_t> Cardinality;
*
* But in our mind the document
*
- * \code{*.xml}
+ * \code{.xml}
* <book>
* <section>
* Text.
@@ -558,7 +558,6 @@ class StructuredClass : public Descriptor {
private:
const Cardinality cardinality;
Owned<StructuredClass> isa;
- NodeVector<FieldDescriptor> parents;
public:
const bool transparent;
@@ -599,7 +598,6 @@ public:
: Descriptor(mgr, std::move(name), domain, attributesDescriptor),
cardinality(cardinality),
isa(acquire(isa)),
- parents(this),
transparent(transparent),
root(root)
{
@@ -620,33 +618,6 @@ public:
* hierarchy (!).
*/
Rooted<StructuredClass> getIsA() const { return isa; }
-
- /**
- * Returns a const reference to the NodeVector of FieldDescriptors that
- * should allow an instance of this StructuredClass as child in the
- * Structure Tree. This enables you to "invade" other domains as described
- * in the StructuredClass documentation.
- *
- * @return a const reference to the NodeVector of FieldDescriptors that
- * should allow an instance of this StructuredClass as child in the
- * Structure Tree.
- */
- const NodeVector<FieldDescriptor> &getParents() const { return parents; }
-
- /**
- * Adds a FieldDescriptor that should allow an instance of this
- * StructuredClass as a child in the Structure Tree.
- */
- void addParent(Handle<FieldDescriptor> p) { parents.push_back(p); }
-
- /**
- * Adds multiple FieldDescriptors that should allow an instance of this
- * StructuredClass as a child in the Structure Tree.
- */
- void addParents(const std::vector<Handle<FieldDescriptor>> &ps)
- {
- parents.insert(parents.end(), ps.begin(), ps.end());
- }
};
/**
diff --git a/test/core/model/DomainTest.cpp b/test/core/model/DomainTest.cpp
index 61de4c4..3b62b48 100644
--- a/test/core/model/DomainTest.cpp
+++ b/test/core/model/DomainTest.cpp
@@ -122,5 +122,34 @@ TEST(Descriptor, pathTo)
// this should be impossible.
ASSERT_EQ(0U, path.size());
}
+
+TEST(Descriptor, pathToAdvanced)
+{
+ // Now we build a really nasty domain with lots of transparency
+ // and inheritance
+ Logger logger;
+ Manager mgr{1};
+ Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
+ // Get the domain.
+ Rooted<Domain> domain {new Domain(mgr, sys, "nasty")};
+ Cardinality any;
+ any.merge(Range<size_t>::typeRangeFrom(0));
+
+ // Our root class A
+ Rooted<StructuredClass> A{new StructuredClass(
+ mgr, "A", domain, any, {nullptr}, {nullptr}, false, true)};
+ domain->addStructuredClass(A);
+ // We also create a field for it.
+ Rooted<FieldDescriptor> A_field{new FieldDescriptor(mgr, A)};
+ A->addFieldDescriptor(A_field);
+
+ // our first transparent child B
+ Rooted<StructuredClass> B{new StructuredClass(
+ mgr, "B", domain, any, {nullptr}, {nullptr}, true)};
+ A_field->addChild(B);
+
+ //TODO: Continue
+}
+
}
}