summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-02-18 21:29:36 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-02-18 21:29:36 +0100
commit5dfa2b6cba3e31d18e2cc23f05d330e387fc1a29 (patch)
tree2f97711bd12bfdb35425c0ffaca5af6a231b8076
parentf6d3495b681e19227a5ea9ec081d36644be55d68 (diff)
parent19e3e43e80e413d297ca8970d018eeda57ee65e1 (diff)
Merge branch 'master' of somweyr.de:ousia
-rw-r--r--data/domain/bibliography.osxml33
-rw-r--r--data/domain/meta.osxml22
-rw-r--r--src/core/common/VariantConverter.cpp4
-rw-r--r--src/core/common/VariantWriter.cpp31
-rw-r--r--src/core/common/VariantWriter.hpp22
-rw-r--r--src/core/model/Domain.cpp37
-rw-r--r--src/core/model/Domain.hpp1
-rw-r--r--src/core/parser/ParserScope.cpp12
-rw-r--r--src/core/parser/ParserScope.hpp18
-rw-r--r--src/core/parser/stack/DocumentHandler.cpp74
-rw-r--r--src/core/parser/stack/DomainHandler.cpp16
-rw-r--r--src/core/parser/stack/Stack.cpp20
-rw-r--r--src/core/parser/stack/TypesystemHandler.cpp20
-rw-r--r--src/formats/osxml/OsxmlEventParser.cpp6
-rw-r--r--src/plugins/xml/XmlOutput.cpp66
-rw-r--r--src/plugins/xml/XmlOutput.hpp2
-rw-r--r--test/core/common/VariantConverterTest.cpp2
-rw-r--r--test/core/model/DomainTest.cpp185
-rw-r--r--test/core/parser/ParserScopeTest.cpp6
-rw-r--r--test/core/parser/stack/StackTest.cpp20
-rw-r--r--test/formats/osml/OsmlParserTest.cpp41
-rw-r--r--test/formats/osxml/OsxmlParserTest.cpp26
-rw-r--r--test/plugins/xml/XmlOutputTest.cpp40
-rw-r--r--testdata/osmlparser/explicit_fields.osml16
-rw-r--r--testdata/osmlparser/invalid_explicit_fields.osml16
-rw-r--r--testdata/osmlparser/struct_with_no_field.osml12
-rw-r--r--testdata/osxmlparser/affiliation.osxml10
-rw-r--r--testdata/osxmlparser/bibliography_domain.osxml26
-rw-r--r--testdata/osxmlparser/color.osxml18
-rw-r--r--testdata/osxmlparser/complex_book.osxml63
-rw-r--r--testdata/osxmlparser/email.osxml8
-rw-r--r--testdata/osxmlparser/generic.osxml37
-rw-r--r--testdata/osxmlparser/lists_domain.osxml26
-rw-r--r--testdata/osxmlparser/meta_domain.osxml35
-rw-r--r--testdata/osxmlparser/test.osxml15
-rw-r--r--testdata/osxmlparser/version.osxml8
36 files changed, 647 insertions, 347 deletions
diff --git a/data/domain/bibliography.osxml b/data/domain/bibliography.osxml
index 11e2606..5953e5f 100644
--- a/data/domain/bibliography.osxml
+++ b/data/domain/bibliography.osxml
@@ -12,16 +12,31 @@
<field name="bibliography" isSubtree="true"/>
</parentRef>
</struct>
-
<struct name="bibEntry">
- <primitive name="name" type="string" isSubtree="true"/>
- <primitive name="year" type="int" isSubtree="true"/>
- <primitive name="journal" type="string" isSubtree="true" optional="true"/>
- <primitive name="pages" type="cardinality" isSubtree="true" optional="true"/>
- <!-- Here a geographical enum or something would be more exact -->
- <primitive name="location" type="string" isSubtree="true" optional="true"/>
- <field name="authors" optional="true">
- <childRef ref="meta.author"/>
+ <field>
+ <childRef ref="meta.authors"/>
+ <childRef ref="title"/>
+ <childRef ref="year"/>
+ <childRef ref="journal"/>
+ <childRef ref="pages"/>
+ <childRef ref="location"/>
</field>
</struct>
+ <struct name="title" cardinality="{1}">
+ <primitive type="string"/>
+ </struct>
+ <struct name="year" cardinality="{1}">
+ <primitive type="int"/>
+ </struct>
+ <struct name="journal" cardinality="{0-1}">
+ <!-- here some kind of database reference would be better -->
+ <primitive type="string"/>
+ </struct>
+ <struct name="pages" cardinality="{0-1}">
+ <primitive type="cardinality"/>
+ </struct>
+ <struct name="location" cardinality="{0-1}">
+ <!-- here some kind of database reference would be better -->
+ <primitive type="string"/>
+ </struct>
</domain>
diff --git a/data/domain/meta.osxml b/data/domain/meta.osxml
index 7e96699..d214921 100644
--- a/data/domain/meta.osxml
+++ b/data/domain/meta.osxml
@@ -9,7 +9,6 @@
<struct name="meta" cardinality="{1}" transparent="true">
<field>
- <childRef ref="title"/>
<childRef ref="author"/>
<childRef ref="version"/>
</field>
@@ -22,21 +21,24 @@
<!-- One could also include "article" and other things here -->
</struct>
- <!-- A title is just a heading -->
- <struct name="title">
- <field>
- <childRef ref="heading"/>
- </field>
- </struct>
-
- <!-- no explicit cardinality, because we might have multiple authors -->
- <struct name="author">
+ <struct name="person">
<primitive isSubtree="true" name="firstName" type="string"/>
<primitive isSubtree="true" name="lastName" type="string"/>
<primitive isSubtree="true" name="email" type="email" optional="true"/>
<primitive isSubtree="true" name="affiliation" type="affiliation" optional="true"/>
</struct>
+ <!-- wrapper author tag to allow specifying no authors whatsoever. But if
+ an author is specified it has to be at least one primary author. -->
+ <struct name="authors" transparent="true" cardinality="{0-1}">
+ <field>
+ <childRef ref="author"/>
+ </field>
+ </struct>
+
+ <!-- no explicit cardinality, because we might have multiple authors -->
+ <struct name="author" isa="person"/>
+
<!-- but we need at least one primary author -->
<struct name="primaryAuthor" cardinality="{>0}" isa="author"/>
diff --git a/src/core/common/VariantConverter.cpp b/src/core/common/VariantConverter.cpp
index a9ca467..b43d04e 100644
--- a/src/core/common/VariantConverter.cpp
+++ b/src/core/common/VariantConverter.cpp
@@ -262,7 +262,7 @@ bool VariantConverter::toString(Variant &var, Logger &logger, Mode mode)
// Print cardinality syntax
Variant::cardinalityType card = var.asCardinality();
std::stringstream ss;
- ss << "<cardinality {";
+ ss << "{";
bool first = true;
for (Variant::rangeType r : card.getRanges()) {
if (first) {
@@ -288,7 +288,7 @@ bool VariantConverter::toString(Variant &var, Logger &logger, Mode mode)
ss << ">" << std::to_string(r.start - 1);
}
}
- ss << "}>";
+ ss << "}";
var = ss.str().c_str();
return true;
}
diff --git a/src/core/common/VariantWriter.cpp b/src/core/common/VariantWriter.cpp
index 427ac5d..b1bafe4 100644
--- a/src/core/common/VariantWriter.cpp
+++ b/src/core/common/VariantWriter.cpp
@@ -104,8 +104,9 @@ static void writeLinebreak(std::ostream &stream, bool pretty)
* @param pretty if true, the resulting value is properly indented.
* @param level is the current indentation level.
*/
-static void writeJsonInternal(const Variant &var, std::ostream &stream,
- bool pretty, int level)
+template <char ObjectStart, char ObjectEnd, char Equals>
+static void writeInternal(const Variant &var, std::ostream &stream, bool pretty,
+ int level)
{
switch (var.getType()) {
case VariantType::NULLPTR:
@@ -127,7 +128,8 @@ static void writeJsonInternal(const Variant &var, std::ostream &stream,
const Variant::arrayType &arr = var.asArray();
for (size_t i = 0; i < arr.size(); i++) {
writeIndentation(stream, pretty, level + 1);
- writeJsonInternal(arr[i], stream, pretty, level + 1);
+ writeInternal<ObjectStart, ObjectEnd, Equals>(
+ arr[i], stream, pretty, level + 1);
if (i + 1 != arr.size()) {
stream << ",";
}
@@ -139,21 +141,22 @@ static void writeJsonInternal(const Variant &var, std::ostream &stream,
}
case VariantType::MAP: {
writeIndentation(stream, pretty, level);
- stream << "{";
+ stream << ObjectStart;
writeLinebreak(stream, pretty);
const Variant::mapType &map = var.asMap();
for (auto it = map.cbegin(); it != map.cend();) {
writeIndentation(stream, pretty, level + 1);
writeJsonString(it->first, stream);
- stream << (pretty ? ": " : ":");
- writeJsonInternal(it->second, stream, pretty, level + 1);
+ stream << Equals << (pretty ? " " : "");
+ writeInternal<ObjectStart, ObjectEnd, Equals>(
+ it->second, stream, pretty, level + 1);
if ((++it) != map.cend()) {
stream << ",";
}
writeLinebreak(stream, pretty);
}
writeIndentation(stream, pretty, level);
- stream << "}";
+ stream << ObjectEnd;
return;
}
}
@@ -162,7 +165,7 @@ static void writeJsonInternal(const Variant &var, std::ostream &stream,
void VariantWriter::writeJson(const Variant &var, std::ostream &stream,
bool pretty)
{
- writeJsonInternal(var, stream, pretty, 0);
+ writeInternal<'{', '}', ':'>(var, stream, pretty, 0);
}
std::string VariantWriter::writeJsonToString(const Variant &var, bool pretty)
@@ -172,6 +175,16 @@ std::string VariantWriter::writeJsonToString(const Variant &var, bool pretty)
return ss.str();
}
-
+void VariantWriter::writeOusia(const Variant &var, std::ostream &stream,
+ bool pretty)
+{
+ writeInternal<'[', ']', '='>(var, stream, pretty, 0);
}
+std::string VariantWriter::writeOusiaToString(const Variant &var, bool pretty)
+{
+ std::stringstream ss;
+ writeOusia(var, ss, pretty);
+ return ss.str();
+}
+} \ No newline at end of file
diff --git a/src/core/common/VariantWriter.hpp b/src/core/common/VariantWriter.hpp
index 7fe32fb..12f4bba 100644
--- a/src/core/common/VariantWriter.hpp
+++ b/src/core/common/VariantWriter.hpp
@@ -59,8 +59,28 @@ public:
* @param var is the variant that should be serialized.
* @param pretty if true, the resulting value is properly indented.
*/
- static std::string writeJsonToString(const Variant &var, bool pretty = true);
+ static std::string writeJsonToString(const Variant &var,
+ bool pretty = true);
+ /**
+ * Dumps the Variant as re-readable ousia data. Note that the resulting
+ * data is invalid if the Variant consists of function or object references.
+ *
+ * @param var is the variant that should be serialized.
+ * @param stream is the stream the result should be written to.
+ * @param pretty if true, the resulting value is properly indented.
+ */
+ static void writeOusia(const Variant &var, std::ostream &stream,
+ bool pretty = true);
+
+ /**
+ * Dumps the Variant as re-readable ousia data to a string.
+ *
+ * @param var is the variant that should be serialized.
+ * @param pretty if true, the resulting value is properly indented.
+ */
+ static std::string writeOusiaToString(const Variant &var,
+ bool pretty = true);
};
}
diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp
index ca8f889..8255401 100644
--- a/src/core/model/Domain.cpp
+++ b/src/core/model/Domain.cpp
@@ -324,21 +324,31 @@ bool FieldDescriptor::doValidate(Logger &logger) const
return valid;
}
-static void gatherSubclasses(NodeVector<StructuredClass> &res,
- Handle<StructuredClass> strct)
+static void gatherSubclasses(
+ std::unordered_set<const StructuredClass *>& visited,
+ NodeVector<StructuredClass> &res, Handle<StructuredClass> 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(res, sub);
+ gatherSubclasses(visited, res, sub);
}
}
NodeVector<StructuredClass> FieldDescriptor::getChildrenWithSubclasses() const
{
+ std::unordered_set<const StructuredClass *> visited;
NodeVector<StructuredClass> res;
for (auto c : children) {
res.push_back(c);
- gatherSubclasses(res, c);
+ gatherSubclasses(visited, res, c);
}
return res;
}
@@ -566,8 +576,9 @@ bool Descriptor::addAndSortFieldDescriptor(Handle<FieldDescriptor> fd,
if (fds.find(fd) == fds.end()) {
invalidate();
// check if the previous field is a tree field already.
- if (!fds.empty() && !fieldDescriptors.empty() &&
- fds.back()->getFieldType() == FieldDescriptor::FieldType::TREE &&
+ 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);
@@ -776,8 +787,13 @@ void StructuredClass::removeSubclass(Handle<StructuredClass> sc, Logger &logger)
Rooted<FieldDescriptor> StructuredClass::gatherFieldDescriptors(
NodeVector<FieldDescriptor> &current,
+ std::unordered_set<const StructuredClass *> &visited,
std::set<std::string> &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<FieldDescriptor> mainField;
NodeVector<FieldDescriptor> tmp;
// first gather the non-overridden fields.
@@ -798,8 +814,8 @@ Rooted<FieldDescriptor> StructuredClass::gatherFieldDescriptors(
if (superclass != nullptr) {
Rooted<FieldDescriptor> super_main_field =
- superclass->gatherFieldDescriptors(current, overriddenFields,
- hasTREE);
+ superclass->gatherFieldDescriptors(current, visited,
+ overriddenFields, hasTREE);
if (!hasTREE) {
mainField = super_main_field;
}
@@ -814,9 +830,10 @@ NodeVector<FieldDescriptor> StructuredClass::getFieldDescriptors() const
{
// in this case we return a NodeVector of Rooted entries without owner.
NodeVector<FieldDescriptor> vec;
+ std::unordered_set<const StructuredClass *> visited;
std::set<std::string> overriddenFields;
Rooted<FieldDescriptor> mainField =
- gatherFieldDescriptors(vec, overriddenFields, false);
+ gatherFieldDescriptors(vec, visited, overriddenFields, false);
if (mainField != nullptr) {
vec.push_back(mainField);
}
@@ -961,4 +978,4 @@ const Rtti Domain = RttiBuilder<ousia::Domain>("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
index 476a38c..b3fc6c2 100644
--- a/src/core/model/Domain.hpp
+++ b/src/core/model/Domain.hpp
@@ -808,6 +808,7 @@ private:
*/
Rooted<FieldDescriptor> gatherFieldDescriptors(
NodeVector<FieldDescriptor> &current,
+ std::unordered_set<const StructuredClass *> &visited,
std::set<std::string> &overriddenFields, bool hasTREE) const;
protected:
diff --git a/src/core/parser/ParserScope.cpp b/src/core/parser/ParserScope.cpp
index b0a4945..dabb03c 100644
--- a/src/core/parser/ParserScope.cpp
+++ b/src/core/parser/ParserScope.cpp
@@ -216,7 +216,7 @@ void ParserScope::push(Handle<Node> node)
nodes.push_back(node);
}
-void ParserScope::pop()
+void ParserScope::pop(Logger &logger)
{
// Make sure pop is not called without an element on the stack
const size_t currentDepth = nodes.size();
@@ -235,10 +235,14 @@ void ParserScope::pop()
flags.resize(newLen);
// Whenever a RootNode is popped from the stack, we have to perform deferred
- // resolution -- however, postpone issuing error messages
- if (nodes.back()->isa(&RttiTypes::RootNode)) {
- Logger logger;
+ // resolution and validate the subtree
+ Rooted<Node> node = nodes.back();
+ if (node->isa(&RttiTypes::RootNode)) {
+ // Perform pending resolutions -- do not issue errors now
performDeferredResolution(logger, true);
+
+ // Perform validation of the subtree.
+ node->validate(logger);
}
// Remove the element from the stack
diff --git a/src/core/parser/ParserScope.hpp b/src/core/parser/ParserScope.hpp
index 24af6b8..e27c81e 100644
--- a/src/core/parser/ParserScope.hpp
+++ b/src/core/parser/ParserScope.hpp
@@ -286,7 +286,13 @@ enum class ParserFlag {
* Set to the boolean value "true" if the head section of a file has passed.
* This happens once the first non-import tag is reached.
*/
- POST_HEAD
+ POST_HEAD,
+
+ /**
+ * Set to the boolean value "true" if explicit fields may no longer be
+ * defined inside a structure element.
+ */
+ POST_EXPLICIT_FIELDS
};
/**
@@ -423,9 +429,14 @@ public:
void push(Handle<Node> node);
/**
- * Removes the last pushed node from the scope.
+ * Removes the last pushed node from the scope. If the node that is popped
+ * from the internal stack is a RootNode, pending resolutions are performed
+ * and the RootNode is validated.
+ *
+ * @param logger is the Logger instance to which error messages should be
+ * logged.
*/
- void pop();
+ void pop(Logger &logger);
/**
* Returns the top-level nodes. These are the nodes that are pushed onto the
@@ -792,6 +803,7 @@ public:
bool resolveFieldDescriptor(const std::string &name, Handle<Node> owner,
Logger &logger,
ResolutionResultCallback resultCallback);
+
/**
* Tries to resolve all currently deferred resolution steps. The list of
* pending deferred resolutions is cleared after this function has run.
diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp
index 35146b1..bb04bd3 100644
--- a/src/core/parser/stack/DocumentHandler.cpp
+++ b/src/core/parser/stack/DocumentHandler.cpp
@@ -47,7 +47,7 @@ bool DocumentHandler::start(Variant::mapType &args)
return true;
}
-void DocumentHandler::end() { scope().pop(); }
+void DocumentHandler::end() { scope().pop(logger()); }
/* DocumentChildHandler */
@@ -98,6 +98,9 @@ void DocumentChildHandler::createPath(const NodeVector<Node> &path,
manager(), scope().getLeaf(),
parent->getDescriptor()->getFieldDescriptorIndex(), true)};
scope().push(field);
+
+ // Generally allow explicit fields in the new field
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, false);
}
void DocumentChildHandler::createPath(const size_t &firstFieldIdx,
@@ -113,6 +116,9 @@ void DocumentChildHandler::createPath(const size_t &firstFieldIdx,
parent = static_cast<DocumentEntity *>(transparent.get());
createPath(path, parent, 2);
+
+ // Generally allow explicit fields in the new field
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, false);
}
bool DocumentChildHandler::start(Variant::mapType &args)
@@ -136,6 +142,14 @@ bool DocumentChildHandler::start(Variant::mapType &args)
Rooted<StructuredEntity> entity;
// handle the root note specifically.
if (parentNode->isa(&RttiTypes::Document)) {
+ // if we already have a root node, stop.
+ if (parentNode.cast<Document>()->getRoot() != nullptr) {
+ logger().warning(
+ "This document already has a root node. The additional "
+ "node is ignored.",
+ location());
+ return false;
+ }
Rooted<StructuredClass> strct = scope().resolve<StructuredClass>(
Utils::split(name(), ':'), logger());
if (strct == nullptr) {
@@ -170,12 +184,25 @@ bool DocumentChildHandler::start(Variant::mapType &args)
ssize_t newFieldIdx =
parent->getDescriptor()->getFieldDescriptorIndex(name());
if (newFieldIdx != -1) {
- Rooted<DocumentField> field{new DocumentField(
- manager(), parentNode, newFieldIdx, false)};
- field->setLocation(location());
- scope().push(field);
- isExplicitField = true;
- return true;
+ // Check whether explicit fields are allowed here, if not
+ if (scope().getFlag(ParserFlag::POST_EXPLICIT_FIELDS)) {
+ logger().note(
+ std::string(
+ "Data or structure commands have already been "
+ "given, command \"") +
+ name() + std::string(
+ "\" is not interpreted explicit "
+ "field. Move explicit field "
+ "references to the beginning."),
+ location());
+ } else {
+ Rooted<DocumentField> field{new DocumentField(
+ manager(), parentNode, newFieldIdx, false)};
+ field->setLocation(location());
+ scope().push(field);
+ isExplicitField = true;
+ return true;
+ }
}
}
@@ -200,9 +227,9 @@ bool DocumentChildHandler::start(Variant::mapType &args)
// if we have transparent elements above us in the structure
// tree we try to unwind them before we give up.
// pop the implicit field.
- scope().pop();
+ scope().pop(logger());
// pop the implicit element.
- scope().pop();
+ scope().pop(logger());
continue;
}
throw LoggableException(
@@ -218,11 +245,17 @@ bool DocumentChildHandler::start(Variant::mapType &args)
parent->getDescriptor()->getFieldDescriptorIndex();
}
// create the entity for the new element at last.
- //TODO: REMOVE
+ // TODO: REMOVE
strct_name = strct->getName();
entity = parent->createChildStructuredEntity(strct, lastFieldIdx,
args, nameAttr);
}
+
+ // We're past the region in which explicit fields can be defined in the
+ // parent structure element
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, true);
+
+ // Bush the entity onto the stack
entity->setLocation(location());
scope().push(entity);
return true;
@@ -237,7 +270,7 @@ void DocumentChildHandler::end()
return;
}
// pop the "main" element.
- scope().pop();
+ scope().pop(logger());
}
bool DocumentChildHandler::fieldStart(bool &isDefault, size_t fieldIdx)
@@ -259,6 +292,9 @@ bool DocumentChildHandler::fieldStart(bool &isDefault, size_t fieldIdx)
parent->getDescriptor()->getFieldDescriptors();
if (isDefault) {
+ if(fields.empty()){
+ return false;
+ }
fieldIdx = fields.size() - 1;
} else {
if (fieldIdx >= fields.size()) {
@@ -271,6 +307,10 @@ bool DocumentChildHandler::fieldStart(bool &isDefault, size_t fieldIdx)
new DocumentField(manager(), parentNode, fieldIdx, false)};
field->setLocation(location());
scope().push(field);
+
+ // Generally allow explicit fields in the new field
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, false);
+
return true;
}
@@ -279,15 +319,15 @@ void DocumentChildHandler::fieldEnd()
assert(scope().getLeaf()->isa(&RttiTypes::DocumentField));
// pop the field from the stack.
- scope().pop();
+ scope().pop(logger());
// pop all remaining transparent elements.
while (scope().getLeaf()->isa(&RttiTypes::StructuredEntity) &&
scope().getLeaf().cast<StructuredEntity>()->isTransparent()) {
// pop the transparent element.
- scope().pop();
+ scope().pop(logger());
// pop the transparent field.
- scope().pop();
+ scope().pop(logger());
}
}
@@ -334,6 +374,10 @@ bool DocumentChildHandler::convertData(Handle<FieldDescriptor> field,
bool DocumentChildHandler::data(Variant &data)
{
+ // We're past the region in which explicit fields can be defined in the
+ // parent structure element
+ scope().setFlag(ParserFlag::POST_EXPLICIT_FIELDS, true);
+
Rooted<Node> parentField = scope().getLeaf();
assert(parentField->isa(&RttiTypes::DocumentField));
@@ -427,4 +471,4 @@ namespace RttiTypes {
const Rtti DocumentField = RttiBuilder<ousia::parser_stack::DocumentField>(
"DocumentField").parent(&Node);
}
-}
+} \ No newline at end of file
diff --git a/src/core/parser/stack/DomainHandler.cpp b/src/core/parser/stack/DomainHandler.cpp
index ddec1ee..aa18faa 100644
--- a/src/core/parser/stack/DomainHandler.cpp
+++ b/src/core/parser/stack/DomainHandler.cpp
@@ -53,7 +53,7 @@ bool DomainHandler::start(Variant::mapType &args)
return true;
}
-void DomainHandler::end() { scope().pop(); }
+void DomainHandler::end() { scope().pop(logger()); }
/* DomainStructHandler */
@@ -85,7 +85,7 @@ bool DomainStructHandler::start(Variant::mapType &args)
return true;
}
-void DomainStructHandler::end() { scope().pop(); }
+void DomainStructHandler::end() { scope().pop(logger()); }
/* DomainAnnotationHandler */
bool DomainAnnotationHandler::start(Variant::mapType &args)
@@ -102,7 +102,7 @@ bool DomainAnnotationHandler::start(Variant::mapType &args)
return true;
}
-void DomainAnnotationHandler::end() { scope().pop(); }
+void DomainAnnotationHandler::end() { scope().pop(logger()); }
/* DomainAttributesHandler */
@@ -118,7 +118,7 @@ bool DomainAttributesHandler::start(Variant::mapType &args)
return true;
}
-void DomainAttributesHandler::end() { scope().pop(); }
+void DomainAttributesHandler::end() { scope().pop(logger()); }
/* DomainFieldHandler */
@@ -148,7 +148,7 @@ bool DomainFieldHandler::start(Variant::mapType &args)
return true;
}
-void DomainFieldHandler::end() { scope().pop(); }
+void DomainFieldHandler::end() { scope().pop(logger()); }
/* DomainFieldRefHandler */
@@ -218,7 +218,7 @@ bool DomainPrimitiveHandler::start(Variant::mapType &args)
return true;
}
-void DomainPrimitiveHandler::end() { scope().pop(); }
+void DomainPrimitiveHandler::end() { scope().pop(logger()); }
/* DomainChildHandler */
@@ -251,7 +251,7 @@ bool DomainParentHandler::start(Variant::mapType &args)
return true;
}
-void DomainParentHandler::end() { scope().pop(); }
+void DomainParentHandler::end() { scope().pop(logger()); }
/* DomainParentFieldHandler */
@@ -414,4 +414,4 @@ namespace RttiTypes {
const Rtti DomainParent = RttiBuilder<ousia::parser_stack::DomainParent>(
"DomainParent").parent(&Node);
}
-} \ No newline at end of file
+}
diff --git a/src/core/parser/stack/Stack.cpp b/src/core/parser/stack/Stack.cpp
index 08f86e5..5b67248 100644
--- a/src/core/parser/stack/Stack.cpp
+++ b/src/core/parser/stack/Stack.cpp
@@ -16,8 +16,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sstream>
-
#include <core/common/Logger.hpp>
#include <core/common/Utils.hpp>
#include <core/common/Exceptions.hpp>
@@ -256,7 +254,9 @@ void Stack::endCurrentHandler()
// Make sure the fieldEnd handler is called if the element still
// is in a field
if (info.inField) {
- info.handler->fieldEnd();
+ if (info.inValidField) {
+ info.handler->fieldEnd();
+ }
info.fieldEnd();
}
@@ -300,8 +300,6 @@ bool Stack::ensureHandlerIsInField()
// Try to start a new default field, abort if this did not work
bool isDefault = true;
if (!info.handler->fieldStart(isDefault, info.fieldIdx)) {
- info.handler->fieldEnd();
- endCurrentHandler();
return false;
}
@@ -505,10 +503,9 @@ void Stack::fieldStart(bool isDefault)
// (the default field always is the last field) -- mark the command as
// invalid
if (info.hadDefaultField) {
- logger().error(
- std::string("Got field start, but command \"") +
- currentCommandName() +
- std::string("\" does not have any more fields"));
+ logger().error(std::string("Got field start, but command \"") +
+ currentCommandName() +
+ std::string("\" does not have any more fields"));
}
// Copy the isDefault flag to a local variable, the fieldStart method will
@@ -559,7 +556,7 @@ void Stack::fieldEnd()
// Only continue if the current handler stack is in a valid state, do not
// call the fieldEnd function if something went wrong before
- if (handlersValid() && !info.hadDefaultField) {
+ if (handlersValid() && !info.hadDefaultField && info.inValidField) {
try {
info.handler->fieldEnd();
}
@@ -587,5 +584,4 @@ void Stack::token(Variant token)
// TODO
}
}
-}
-
+} \ No newline at end of file
diff --git a/src/core/parser/stack/TypesystemHandler.cpp b/src/core/parser/stack/TypesystemHandler.cpp
index 8fd9525..de8ee49 100644
--- a/src/core/parser/stack/TypesystemHandler.cpp
+++ b/src/core/parser/stack/TypesystemHandler.cpp
@@ -16,11 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <core/model/Typesystem.hpp>
+#include <core/model/Document.hpp>
#include <core/model/Domain.hpp>
+#include <core/model/Typesystem.hpp>
#include <core/parser/ParserScope.hpp>
#include <core/parser/ParserContext.hpp>
+#include "DocumentHandler.hpp"
#include "DomainHandler.hpp"
#include "State.hpp"
#include "TypesystemHandler.hpp"
@@ -38,10 +40,16 @@ bool TypesystemHandler::start(Variant::mapType &args)
typesystem->setLocation(location());
// If the typesystem is defined inside a domain, add a reference to the
- // typesystem to the domain
+ // typesystem to the domain -- do the same with a document, if no domain
+ // is found
Rooted<Domain> domain = scope().select<Domain>();
if (domain != nullptr) {
domain->reference(typesystem);
+ } else {
+ Rooted<Document> document = scope().select<Document>();
+ if (document != nullptr) {
+ document->reference(typesystem);
+ }
}
// Push the typesystem onto the scope, set the POST_HEAD flag to true
@@ -51,7 +59,7 @@ bool TypesystemHandler::start(Variant::mapType &args)
return true;
}
-void TypesystemHandler::end() { scope().pop(); }
+void TypesystemHandler::end() { scope().pop(logger()); }
/* TypesystemEnumHandler */
@@ -70,7 +78,7 @@ bool TypesystemEnumHandler::start(Variant::mapType &args)
return true;
}
-void TypesystemEnumHandler::end() { scope().pop(); }
+void TypesystemEnumHandler::end() { scope().pop(logger()); }
/* TypesystemEnumEntryHandler */
@@ -112,7 +120,7 @@ bool TypesystemStructHandler::start(Variant::mapType &args)
return true;
}
-void TypesystemStructHandler::end() { scope().pop(); }
+void TypesystemStructHandler::end() { scope().pop(logger()); }
/* TypesystemStructFieldHandler */
@@ -182,7 +190,7 @@ bool TypesystemConstantHandler::start(Variant::mapType &args)
namespace States {
const State Typesystem = StateBuilder()
- .parents({&None, &Domain})
+ .parents({&None, &Domain, &Document})
.createdNodeType(&RttiTypes::Typesystem)
.elementHandler(TypesystemHandler::create)
.arguments({Argument::String("name", "")});
diff --git a/src/formats/osxml/OsxmlEventParser.cpp b/src/formats/osxml/OsxmlEventParser.cpp
index 788f376..c9254b0 100644
--- a/src/formats/osxml/OsxmlEventParser.cpp
+++ b/src/formats/osxml/OsxmlEventParser.cpp
@@ -253,6 +253,12 @@ static void xmlStartElementHandler(void *ref, const XML_Char *name,
// Convert the C string to a std::string
const std::string key{*(attr++)};
+ // Ignore xml namespace declarations
+ if (Utils::startsWith(key, "xmlns:") && parser->getData().depth == 1) {
+ attr++;
+ continue;
+ }
+
// Search the location of the key
SourceLocation keyLoc;
auto it = attributeOffsets.find(key);
diff --git a/src/plugins/xml/XmlOutput.cpp b/src/plugins/xml/XmlOutput.cpp
index 37d95ec..8af29fd 100644
--- a/src/plugins/xml/XmlOutput.cpp
+++ b/src/plugins/xml/XmlOutput.cpp
@@ -16,6 +16,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <cassert>
+
#include "XmlOutput.hpp"
#include <core/common/Variant.hpp>
@@ -94,7 +96,7 @@ static std::string toString(Variant v, bool pretty)
if (v.isString()) {
return v.asString();
} else {
- return VariantWriter::writeJsonToString(v, pretty);
+ return VariantWriter::writeOusiaToString(v, pretty);
}
}
@@ -137,26 +139,40 @@ void XmlTransformer::transformChildren(DocumentEntity *parentEntity,
Rooted<FieldDescriptor> fieldDesc = fieldDescs[f];
// if this is not the default field create an intermediate node for it.
Rooted<Element> par = parent;
- if (fieldDesc->getFieldType() != FieldDescriptor::FieldType::TREE &&
- !fieldDesc->isPrimitive()) {
+ if (fieldDesc->getFieldType() != FieldDescriptor::FieldType::TREE) {
par =
Rooted<Element>{new Element(mgr, parent, fieldDesc->getName())};
parent->addChild(par);
}
- for (auto c : field) {
- // transform each child.
- Rooted<Node> child;
- if (c->isa(&RttiTypes::StructuredEntity)) {
- child = transformStructuredEntity(
- par, c.cast<StructuredEntity>(), logger, pretty);
- } else if (c->isa(&RttiTypes::DocumentPrimitive)) {
- child = transformPrimitive(par, c.cast<DocumentPrimitive>(),
- logger, pretty);
- } else {
- child = transformAnchor(par, c.cast<Anchor>(), logger, pretty);
+ if (!fieldDesc->isPrimitive()) {
+ for (auto c : field) {
+ // transform each child.
+ Rooted<Element> child;
+ if (c->isa(&RttiTypes::StructuredEntity)) {
+ child = transformStructuredEntity(
+ par, c.cast<StructuredEntity>(), logger, pretty);
+ } else {
+ assert(c->isa(&RttiTypes::Anchor));
+ child =
+ transformAnchor(par, c.cast<Anchor>(), logger, pretty);
+ }
+ if (child != nullptr) {
+ par->addChild(child);
+ }
+ }
+
+ } else {
+ // if the field is primitive we expect a single child.
+ if (field.empty()) {
+ continue;
}
- if (child != nullptr) {
- par->addChild(child);
+ assert(field.size() == 1);
+ assert(field[0]->isa(&RttiTypes::DocumentPrimitive));
+ Rooted<DocumentPrimitive> prim = field[0].cast<DocumentPrimitive>();
+ // transform the primitive content.
+ Rooted<Text> text = transformPrimitive(par, fieldDesc->getPrimitiveType(), prim, logger, pretty);
+ if(text != nullptr){
+ par->addChild(text);
}
}
}
@@ -217,12 +233,28 @@ Rooted<Element> XmlTransformer::transformAnchor(Handle<Element> parent,
}
Rooted<Text> XmlTransformer::transformPrimitive(Handle<Element> parent,
+ Handle<Type> type,
Handle<DocumentPrimitive> p,
Logger &logger, bool pretty)
{
Manager &mgr = parent->getManager();
// transform the primitive content.
- Rooted<Text> text{new Text(mgr, parent, toString(p->getContent(), pretty))};
+ Variant content = p->getContent();
+ if(!type->build(content, logger)){
+ return nullptr;
+ }
+ // special treatment for struct types because they get built as arrays,
+ // which is not so nice for output purposes.
+ if(type->isa(&RttiTypes::StructType)){
+ Variant::mapType map;
+ Variant::arrayType arr = content.asArray();
+ size_t a = 0;
+ for(Handle<Attribute> attr : type.cast<StructType>()->getAttributes()){
+ map.emplace(attr->getName(), arr[a++]);
+ }
+ content = std::move(map);
+ }
+ Rooted<Text> text{new Text(mgr, parent, toString(content, pretty))};
return text;
}
}
diff --git a/src/plugins/xml/XmlOutput.hpp b/src/plugins/xml/XmlOutput.hpp
index 24f2d49..d0caf62 100644
--- a/src/plugins/xml/XmlOutput.hpp
+++ b/src/plugins/xml/XmlOutput.hpp
@@ -53,7 +53,7 @@ private:
Rooted<Element> transformAnchor(Handle<Element> parent, Handle<Anchor> a,
Logger &logger, bool pretty);
- Rooted<Text> transformPrimitive(Handle<Element> parent,
+ Rooted<Text> transformPrimitive(Handle<Element> parent,Handle<Type> type,
Handle<DocumentPrimitive> p, Logger &logger,
bool pretty);
diff --git a/test/core/common/VariantConverterTest.cpp b/test/core/common/VariantConverterTest.cpp
index 9654a7b..2860777 100644
--- a/test/core/common/VariantConverterTest.cpp
+++ b/test/core/common/VariantConverterTest.cpp
@@ -244,7 +244,7 @@ TEST(VariantConverter, toString)
VariantConverter::Mode::ALL, logger);
assertStringConversion(M, "{\"b\":true,\"d\":2.7,\"i\":6,\"s\":\"test\"}",
true, VariantConverter::Mode::ALL, logger);
- assertStringConversion(C, "<cardinality {2-4, >6}>", true,
+ assertStringConversion(C, "{2-4, >6}", true,
VariantConverter::Mode::ALL, logger);
}
diff --git a/test/core/model/DomainTest.cpp b/test/core/model/DomainTest.cpp
index d68648e..6bbf26d 100644
--- a/test/core/model/DomainTest.cpp
+++ b/test/core/model/DomainTest.cpp
@@ -81,6 +81,115 @@ TEST(Domain, testDomainResolving)
assert_path(res[0], &RttiTypes::StructuredClass, {"book", "paragraph"});
}
+// i use this wrapper due to the strange behaviour of GTEST.
+static void assertFalse(bool b){
+ ASSERT_FALSE(b);
+}
+
+static Rooted<FieldDescriptor> createUnsortedPrimitiveField(
+ Handle<StructuredClass> strct, Handle<Type> type, Logger &logger, bool tree,
+ std::string name)
+{
+ FieldDescriptor::FieldType fieldType = FieldDescriptor::FieldType::SUBTREE;
+ if (tree) {
+ fieldType = FieldDescriptor::FieldType::TREE;
+ }
+
+ auto res = strct->createPrimitiveFieldDescriptor(type, logger, fieldType,
+ std::move(name));
+ assertFalse(res.second);
+ return res.first;
+}
+
+TEST(StructuredClass, getFieldDescriptors)
+{
+ /*
+ * We construct a case with the three levels:
+ * 1.) A has the SUBTREE fields a and b as well as a TREE field.
+ * 2.) B is a subclass of A and has the SUBTREE fields b and c as well as
+ * a TREE field.
+ * 3.) C is a subclass of B and has the SUBTREE field a.
+ * As a result we expect C to have none of As fields, the TREE field of B,
+ * and the SUBTREE fields a (of C) , b and c (of B).
+ */
+ TerminalLogger logger{std::cout};
+ Manager mgr{1};
+ Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
+ Rooted<Domain> domain{new Domain(mgr, sys, "myDomain")};
+
+ Rooted<StructuredClass> A{new StructuredClass(
+ mgr, "A", domain, Cardinality::any(), nullptr, false, true)};
+ Rooted<FieldDescriptor> A_a = createUnsortedPrimitiveField(
+ A, sys->getStringType(), logger, false, "a");
+ Rooted<FieldDescriptor> A_b = createUnsortedPrimitiveField(
+ A, sys->getStringType(), logger, false, "b");
+ Rooted<FieldDescriptor> A_main = createUnsortedPrimitiveField(
+ A, sys->getStringType(), logger, true, "somename");
+
+ Rooted<StructuredClass> B{new StructuredClass(
+ mgr, "B", domain, Cardinality::any(), A, false, true)};
+ Rooted<FieldDescriptor> B_b = createUnsortedPrimitiveField(
+ B, sys->getStringType(), logger, false, "b");
+ Rooted<FieldDescriptor> B_c = createUnsortedPrimitiveField(
+ B, sys->getStringType(), logger, false, "c");
+ Rooted<FieldDescriptor> B_main = createUnsortedPrimitiveField(
+ B, sys->getStringType(), logger, true, "othername");
+
+ Rooted<StructuredClass> C{new StructuredClass(
+ mgr, "C", domain, Cardinality::any(), B, false, true)};
+ Rooted<FieldDescriptor> C_a = createUnsortedPrimitiveField(
+ C, sys->getStringType(), logger, false, "a");
+
+ ASSERT_TRUE(domain->validate(logger));
+
+ // check all FieldDescriptors
+ {
+ NodeVector<FieldDescriptor> fds = A->getFieldDescriptors();
+ ASSERT_EQ(3, fds.size());
+ ASSERT_EQ(A_a, fds[0]);
+ ASSERT_EQ(A_b, fds[1]);
+ ASSERT_EQ(A_main, fds[2]);
+ }
+ {
+ NodeVector<FieldDescriptor> fds = B->getFieldDescriptors();
+ ASSERT_EQ(4, fds.size());
+ ASSERT_EQ(A_a, fds[0]);
+ ASSERT_EQ(B_b, fds[1]);
+ ASSERT_EQ(B_c, fds[2]);
+ ASSERT_EQ(B_main, fds[3]);
+ }
+ {
+ NodeVector<FieldDescriptor> fds = C->getFieldDescriptors();
+ ASSERT_EQ(4, fds.size());
+ ASSERT_EQ(B_b, fds[0]);
+ ASSERT_EQ(B_c, fds[1]);
+ // superclass fields come before subclass fields (except for the TREE
+ // field, which is always last).
+ ASSERT_EQ(C_a, fds[2]);
+ ASSERT_EQ(B_main, fds[3]);
+ }
+}
+
+
+TEST(StructuredClass, getFieldDescriptorsCycles)
+{
+ Logger logger;
+ Manager mgr{1};
+ Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
+ Rooted<Domain> domain{new Domain(mgr, sys, "myDomain")};
+
+ Rooted<StructuredClass> A{new StructuredClass(
+ mgr, "A", domain, Cardinality::any(), nullptr, false, true)};
+ A->addSubclass(A, logger);
+ Rooted<FieldDescriptor> A_a = createUnsortedPrimitiveField(
+ A, sys->getStringType(), logger, false, "a");
+ ASSERT_FALSE(domain->validate(logger));
+ // if we call getFieldDescriptors that should still return a valid result.
+ NodeVector<FieldDescriptor> fds = A->getFieldDescriptors();
+ ASSERT_EQ(1, fds.size());
+ ASSERT_EQ(A_a, fds[0]);
+}
+
Rooted<StructuredClass> getClass(const std::string name, Handle<Domain> dom)
{
std::vector<ResolutionResult> res =
@@ -221,6 +330,34 @@ TEST(Descriptor, pathToAdvanced)
ASSERT_EQ("", path[2]->getName());
}
+TEST(Descriptor, pathToCycles)
+{
+ // build a domain with a cycle.
+ Manager mgr{1};
+ Logger logger;
+ Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
+ // Construct the domain
+ Rooted<Domain> domain{new Domain(mgr, sys, "cycles")};
+ Rooted<StructuredClass> A{new StructuredClass(
+ mgr, "A", domain, Cardinality::any(), {nullptr}, true, true)};
+ A->addSubclass(A, logger);
+ ASSERT_FALSE(domain->validate(logger));
+ Rooted<StructuredClass> B{new StructuredClass(
+ mgr, "B", domain, Cardinality::any(), {nullptr}, false, true)};
+ Rooted<FieldDescriptor> A_field = A->createFieldDescriptor(logger).first;
+ A_field->addChild(B);
+ /*
+ * Now try to create the path from A to B. A direct path is possible but
+ * in the worst case this could also try to find shorter paths via an
+ * endless repition of A instances.
+ * As we cut the search tree at paths that are longer than our current
+ * optimum this should not happen, though.
+ */
+ NodeVector<Node> path = A->pathTo(B, logger);
+ ASSERT_EQ(1, path.size());
+ ASSERT_EQ(A_field, path[0]);
+}
+
TEST(Descriptor, getDefaultFields)
{
// construct a domain with lots of default fields to test.
@@ -301,6 +438,29 @@ TEST(Descriptor, getDefaultFields)
ASSERT_EQ(F_field, fields[1]);
}
+TEST(Descriptor, getDefaultFieldsCycles)
+{
+ // build a domain with a cycle.
+ Manager mgr{1};
+ Logger logger;
+ Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
+ // Construct the domain
+ Rooted<Domain> domain{new Domain(mgr, sys, "cycles")};
+ Rooted<StructuredClass> A{new StructuredClass(
+ mgr, "A", domain, Cardinality::any(), {nullptr}, true, true)};
+ A->addSubclass(A, logger);
+ ASSERT_FALSE(domain->validate(logger));
+ Rooted<FieldDescriptor> A_field =
+ A->createPrimitiveFieldDescriptor(sys->getStringType(), logger).first;
+ /*
+ * Now try to get the default fields of A. This should not lead to cycles
+ * if we correctly note all already visited nodes.
+ */
+ NodeVector<FieldDescriptor> defaultFields = A->getDefaultFields();
+ ASSERT_EQ(1, defaultFields.size());
+ ASSERT_EQ(A_field, defaultFields[0]);
+}
+
TEST(Descriptor, getPermittedChildren)
{
// analyze the book domain.
@@ -338,6 +498,31 @@ TEST(Descriptor, getPermittedChildren)
ASSERT_EQ(sub, children[3]);
}
+TEST(Descriptor, getPermittedChildrenCycles)
+{
+ // build a domain with a cycle.
+ Manager mgr{1};
+ Logger logger;
+ Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
+ // Construct the domain
+ Rooted<Domain> domain{new Domain(mgr, sys, "cycles")};
+ Rooted<StructuredClass> A{new StructuredClass(
+ mgr, "A", domain, Cardinality::any(), {nullptr}, true, true)};
+ A->addSubclass(A, logger);
+ ASSERT_FALSE(domain->validate(logger));
+ Rooted<FieldDescriptor> A_field = A->createFieldDescriptor(logger).first;
+ // we make the cycle worse by adding A as child of itself.
+ A_field->addChild(A);
+ /*
+ * Now try to get the permitted children of A. This should not lead to
+ * cycles
+ * if we correctly note all already visited nodes.
+ */
+ NodeVector<StructuredClass> children = A->getPermittedChildren();
+ ASSERT_EQ(1, children.size());
+ ASSERT_EQ(A, children[0]);
+}
+
TEST(StructuredClass, isSubclassOf)
{
// create an inheritance hierarchy.
diff --git a/test/core/parser/ParserScopeTest.cpp b/test/core/parser/ParserScopeTest.cpp
index 7f89f2c..2ead924 100644
--- a/test/core/parser/ParserScopeTest.cpp
+++ b/test/core/parser/ParserScopeTest.cpp
@@ -18,6 +18,7 @@
#include <gtest/gtest.h>
+#include <core/common/Logger.hpp>
#include <core/managed/Manager.hpp>
#include <core/model/Node.hpp>
#include <core/parser/ParserScope.hpp>
@@ -26,6 +27,7 @@ namespace ousia {
TEST(ParserScope, flags)
{
+ Logger logger;
Manager mgr;
ParserScope scope;
@@ -42,9 +44,9 @@ TEST(ParserScope, flags)
ASSERT_TRUE(scope.getFlag(ParserFlag::POST_HEAD));
scope.setFlag(ParserFlag::POST_HEAD, false);
ASSERT_FALSE(scope.getFlag(ParserFlag::POST_HEAD));
- scope.pop();
+ scope.pop(logger);
ASSERT_TRUE(scope.getFlag(ParserFlag::POST_HEAD));
- scope.pop();
+ scope.pop(logger);
ASSERT_FALSE(scope.getFlag(ParserFlag::POST_HEAD));
scope.setFlag(ParserFlag::POST_HEAD, true);
ASSERT_TRUE(scope.getFlag(ParserFlag::POST_HEAD));
diff --git a/test/core/parser/stack/StackTest.cpp b/test/core/parser/stack/StackTest.cpp
index e25f487..a93f14a 100644
--- a/test/core/parser/stack/StackTest.cpp
+++ b/test/core/parser/stack/StackTest.cpp
@@ -449,10 +449,10 @@ TEST(Stack, noImplicitDefaultFieldOnIncompatibleCommand)
tracker.fieldStartResult = false;
s.command("b", {});
- tracker.expect(2, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(2, 1, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_EQ("b", s.currentCommandName());
}
- tracker.expect(2, 2, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(2, 2, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_FALSE(logger.hasError());
}
@@ -563,9 +563,9 @@ TEST(Stack, invalidDefaultField)
tracker.fieldStartResult = false;
s.fieldStart(true);
s.fieldEnd();
- tracker.expect(1, 0, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 0, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
- tracker.expect(1, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 1, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_FALSE(logger.hasError());
}
@@ -583,9 +583,9 @@ TEST(Stack, errorInvalidDefaultFieldData)
s.data("test");
ASSERT_TRUE(logger.hasError());
s.fieldEnd();
- tracker.expect(1, 0, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 0, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
- tracker.expect(1, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 1, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
TEST(Stack, errorInvalidFieldData)
@@ -602,9 +602,9 @@ TEST(Stack, errorInvalidFieldData)
ASSERT_TRUE(logger.hasError());
s.data("test");
s.fieldEnd();
- tracker.expect(1, 0, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 0, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
- tracker.expect(1, 1, 1, 1, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
+ tracker.expect(1, 1, 1, 0, 0, 0, 0); // sc, ec, fsc, fse, asc, aec, dc
}
TEST(Stack, errorFieldStartNoCommand)
@@ -743,7 +743,5 @@ TEST(Stack, fieldAfterDefaultField)
tracker.expect(2, 2, 3, 3, 0, 0, 2); // sc, ec, fsc, fse, asc, aec, dc
ASSERT_FALSE(logger.hasError());
}
-
-}
}
-
+} \ No newline at end of file
diff --git a/test/formats/osml/OsmlParserTest.cpp b/test/formats/osml/OsmlParserTest.cpp
index 3472e5f..5127b32 100644
--- a/test/formats/osml/OsmlParserTest.cpp
+++ b/test/formats/osml/OsmlParserTest.cpp
@@ -158,5 +158,46 @@ TEST(OsmlParser, structureInheritance)
ASSERT_TRUE(node != nullptr);
ASSERT_TRUE(node->isa(&RttiTypes::Domain));
}
+
+TEST(OsmlParser, structWithNoField)
+{
+ OsmlStandaloneEnvironment env(logger);
+ logger.reset();
+
+ Rooted<Node> node = env.parse("struct_with_no_field.osml", "", "",
+ RttiSet{&RttiTypes::Node});
+ ASSERT_FALSE(logger.hasError());
+
+ ASSERT_TRUE(node != nullptr);
+ ASSERT_TRUE(node->isa(&RttiTypes::Document));
+}
+
+TEST(OsmlParser, invalidExplicitFields)
+{
+ OsmlStandaloneEnvironment env(logger);
+ logger.reset();
+
+ ASSERT_FALSE(logger.hasError());
+ Rooted<Node> node = env.parse("invalid_explicit_fields.osml", "", "",
+ RttiSet{&RttiTypes::Node});
+ ASSERT_TRUE(logger.hasError());
+
+ ASSERT_TRUE(node != nullptr);
+ ASSERT_TRUE(node->isa(&RttiTypes::Document));
+}
+
+TEST(OsmlParser, explicitFields)
+{
+ OsmlStandaloneEnvironment env(logger);
+ logger.reset();
+
+ Rooted<Node> node = env.parse("explicit_fields.osml", "", "",
+ RttiSet{&RttiTypes::Node});
+ ASSERT_FALSE(logger.hasError());
+
+ ASSERT_TRUE(node != nullptr);
+ ASSERT_TRUE(node->isa(&RttiTypes::Document));
+}
+
}
diff --git a/test/formats/osxml/OsxmlParserTest.cpp b/test/formats/osxml/OsxmlParserTest.cpp
index 5cc0669..3bf4a47 100644
--- a/test/formats/osxml/OsxmlParserTest.cpp
+++ b/test/formats/osxml/OsxmlParserTest.cpp
@@ -66,15 +66,6 @@ TEST(OsxmlParser, mismatchedTag)
ASSERT_TRUE(logger.hasError());
}
-TEST(OsxmlParser, generic)
-{
- XmlStandaloneEnvironment env(logger);
- env.parse("generic.osxml", "", "", RttiSet{&RttiTypes::Node});
-#ifdef MANAGER_GRAPHVIZ_EXPORT
- env.manager.exportGraphviz("xmlDocument.dot");
-#endif
-}
-
static void checkAttributes(Handle<StructType> expected,
Handle<Descriptor> desc)
{
@@ -347,6 +338,7 @@ static void checkText(Handle<Node> p, Handle<Node> expectedParent,
TEST(OsxmlParser, documentParsing)
{
+ logger.reset();
XmlStandaloneEnvironment env(logger);
Rooted<Node> book_document_node =
env.parse("simple_book.osxml", "", "", RttiSet{&RttiTypes::Document});
@@ -391,5 +383,21 @@ TEST(OsxmlParser, documentParsing)
}
}
}
+
+
+TEST(OsxmlParser, complexDocumentParsing)
+{
+ logger.reset();
+ XmlStandaloneEnvironment env(logger);
+ Rooted<Node> book_document_node =
+ env.parse("complex_book.osxml", "", "", RttiSet{&RttiTypes::Document});
+ ASSERT_FALSE(logger.hasError());
+ ASSERT_FALSE(book_document_node == nullptr);
+ ASSERT_TRUE(book_document_node->isa(&RttiTypes::Document));
+ Rooted<Document> doc = book_document_node.cast<Document>();
+ ASSERT_TRUE(doc->validate(logger));
+ ASSERT_FALSE(logger.hasError());
+}
+
}
diff --git a/test/plugins/xml/XmlOutputTest.cpp b/test/plugins/xml/XmlOutputTest.cpp
index 403078d..fcf72d2 100644
--- a/test/plugins/xml/XmlOutputTest.cpp
+++ b/test/plugins/xml/XmlOutputTest.cpp
@@ -107,5 +107,45 @@ TEST(DemoHTMLTransformer, AnnotationProcessing)
"><book:text>blub</book:text><a:end:emphasized/"
"><book:text>bla</book:text><a:end:strong/>") != std::string::npos);
}
+
+TEST(DemoHTMLTransformer, PrimitiveSubtreeFields)
+{
+ // Construct Manager
+ TerminalLogger logger{std::cerr, true};
+ Manager mgr{1};
+ Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
+ // Construct a simple domain.
+ Rooted<Domain> domain{new Domain(mgr, sys, "myDomain")};
+
+ Rooted<StructuredClass> A{new StructuredClass(
+ mgr, "A", domain, Cardinality::any(), nullptr, false, true)};
+ Rooted<FieldDescriptor> A_a =
+ A->createPrimitiveFieldDescriptor(sys->getStringType(), logger,
+ FieldDescriptor::FieldType::SUBTREE,
+ "a").first;
+ Rooted<FieldDescriptor> A_b =
+ A->createPrimitiveFieldDescriptor(sys->getStringType(), logger,
+ FieldDescriptor::FieldType::SUBTREE,
+ "b").first;
+ Rooted<FieldDescriptor> A_main =
+ A->createPrimitiveFieldDescriptor(sys->getStringType(), logger).first;
+ ASSERT_TRUE(domain->validate(logger));
+ // Construct a document for it.
+ Rooted<Document> doc{new Document(mgr, "myDoc")};
+ Rooted<StructuredEntity> A_impl = doc->createRootStructuredEntity(A);
+ A_impl->createChildDocumentPrimitive("test_a", "a");
+ A_impl->createChildDocumentPrimitive("test_b", "b");
+ A_impl->createChildDocumentPrimitive("test");
+ ASSERT_TRUE(doc->validate(logger));
+ // now transform this document.
+ ResourceManager dummy;
+ XmlTransformer transformer;
+ std::stringstream out;
+ transformer.writeXml(doc, out, logger, dummy, false);
+ const std::string res = out.str();
+ ASSERT_TRUE(
+ res.find("<myDomain:A><a>test_a</a><b>test_b</b>test</myDomain:A>") !=
+ std::string::npos);
+}
}
} \ No newline at end of file
diff --git a/testdata/osmlparser/explicit_fields.osml b/testdata/osmlparser/explicit_fields.osml
new file mode 100644
index 0000000..a9ba1a3
--- /dev/null
+++ b/testdata/osmlparser/explicit_fields.osml
@@ -0,0 +1,16 @@
+\document
+
+\domain#test
+ \struct#a[isRoot=true]
+ \primitive#b[type=string,isSubtree=true]
+ \primitive#c[type=string,isSubtree=true]
+ \primitive#d[type=string,isSubtree=false]
+
+
+\a{!
+ \b{test}
+ \c{test}
+ test
+ test
+ test
+}
diff --git a/testdata/osmlparser/invalid_explicit_fields.osml b/testdata/osmlparser/invalid_explicit_fields.osml
new file mode 100644
index 0000000..9986204
--- /dev/null
+++ b/testdata/osmlparser/invalid_explicit_fields.osml
@@ -0,0 +1,16 @@
+\document
+
+\domain#test
+ \struct#a[isRoot=true]
+ \primitive#b[type=string,isSubtree=true]
+ \primitive#c[type=string,isSubtree=true]
+ \primitive#d[type=string,isSubtree=false]
+
+
+\a{!
+ \b{test}
+ test
+ \c{test}
+ test
+ test
+}
diff --git a/testdata/osmlparser/struct_with_no_field.osml b/testdata/osmlparser/struct_with_no_field.osml
new file mode 100644
index 0000000..8cf2d02
--- /dev/null
+++ b/testdata/osmlparser/struct_with_no_field.osml
@@ -0,0 +1,12 @@
+\document
+
+\domain#test
+ \struct#a[isRoot=true]
+ \field
+ \childRef[ref=b]
+ \struct#b
+
+\a
+ \b
+ \b
+
diff --git a/testdata/osxmlparser/affiliation.osxml b/testdata/osxmlparser/affiliation.osxml
deleted file mode 100644
index d84dc30..0000000
--- a/testdata/osxmlparser/affiliation.osxml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" standalone="yes"?>
-<typesystem name="affiliation">
- <struct name="affiliation">
- <field name="workgroup" type="string"/>
- <field name="departement" type="string"/>
- <field name="institution" type="string"/>
- </struct>
-
- <constant name="citec.sc" type="affiliation" value="[workgroup=Semantic Computing Group,departement=Center of Excellence Cognitive Interaction Technology (CITEC), institution=Bielefeld University]"/>
-</typesystem>
diff --git a/testdata/osxmlparser/bibliography_domain.osxml b/testdata/osxmlparser/bibliography_domain.osxml
deleted file mode 100644
index 53ba531..0000000
--- a/testdata/osxmlparser/bibliography_domain.osxml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0"?>
-<domain name="bibliography">
-
- <import rel="domain" src="./book_domain.osxml"/>
- <import rel="domain" src="./meta_domain.osxml"/>
-
- <struct name="bibliography" transparent="true">
- <field>
- <childRef ref="bibEntry"/>
- </field>
- <parentRef ref="book">
- <field name="bibliography" isSubtree="true"/>
- </parentRef>
- </struct>
- <struct name="bibEntry">
- <primitive name="name" type="string" isSubtree="true"/>
- <primitive name="year" type="int" isSubtree="true"/>
- <primitive name="journal" type="string" isSubtree="true" optional="true"/>
- <primitive name="pages" type="cardinality" isSubtree="true" optional="true"/>
- <!-- Here a geographical enum or something would be more exact -->
- <primitive name="location" type="string" isSubtree="true" optional="true"/>
- <field name="authors" optional="true">
- <childRef ref="meta.author"/>
- </field>
- </struct>
-</domain>
diff --git a/testdata/osxmlparser/color.osxml b/testdata/osxmlparser/color.osxml
deleted file mode 100644
index 17adea4..0000000
--- a/testdata/osxmlparser/color.osxml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" standalone="yes"?>
-<typesystem name="color">
- <struct name="color">
- <field name="r" type="int"/>
- <field name="g" type="int"/>
- <field name="b" type="int"/>
- </struct>
-
- <constant name="aquamarine1" type="color" value="[127,255,212]"/>
- <constant name="aquamarine2" type="color" value="[118,238,198]"/>
- <constant name="aquamarine3" type="color" value="[102,205,170]"/>
- <constant name="aquamarine" type="color" value="[127,255,212]"/>
- <constant name="azure1" type="color" value="[240,255,255]"/>
- <constant name="azure2" type="color" value="[224,238,238]"/>
- <constant name="azure3" type="color" value="[193,205,205]"/>
- <constant name="azure4" type="color" value="[131,139,139]"/>
- <constant name="azure" type="color" value="[240,255,255]"/>
-</typesystem>
diff --git a/testdata/osxmlparser/complex_book.osxml b/testdata/osxmlparser/complex_book.osxml
index b610454..8fff93d 100644
--- a/testdata/osxmlparser/complex_book.osxml
+++ b/testdata/osxmlparser/complex_book.osxml
@@ -1,13 +1,12 @@
<?xml version="1.0"?>
<document>
- <import rel="domain" src="./book_domain.osxml"/>
- <import rel="domain" src="./headings_domain.osxml"/>
- <import rel="domain" src="./meta_domain.osxml"/>
- <import rel="domain" src="./bibliography_domain.osxml"/>
+ <import rel="domain" src="book"/>
+ <import rel="domain" src="headings"/>
+ <import rel="domain" src="meta"/>
+ <import rel="domain" src="bibliography"/>
<!--<import rel="domain" src="emphasis.oxm"/>
<import rel="domain" src="comments.oxm"/>
- <import rel="domain" src="lists.oxm"/>
<alias tag="paragraph" aka="p"/>
<alias tag="emphasized" aka="em"/>-->
@@ -19,40 +18,18 @@
<email>[ikant,philo.albertus-koenigsberg,de]</email>
<affiliation>[Logic and Metaphysics, Faculty of Philosophy, Albertus-University Königsberg]</affiliation>
</primaryAuthor>
- <!-- Using this version tag leads to a very interesting bug:
- A new transparent meta element gets created for it. Because only
- one meta tag is allowed this leads to an error. So what to do?
-
- <version>[1,0,0]</version> -->
+ <version>[1,0,0]</version>
</meta>
-
- <heading>
- Beantwortung der Frage: Was ist Aufklärung?
- </heading>
-
- <chapter name="content">
- <heading>Was ist Aufklärung?</heading>
-
- Aufklärung ist der Ausgang des Menschen aus seiner
- selbstverschuldeten Unmündigkeit. Unmündigkeit ist
- das Unvermögen, sich seines Verstandes ohne Leitung eines anderen zu
- bedienen. Selbstverschuldet ist diese Unmündigkeit, wenn
- die Ursache derselben nicht am Mangel des Verstandes, sondern der
- Entschließung und des Mutes liegt, sich seiner ohne Leitung eines
- andern zu bedienen.
- Sapere aude! Habe Mut, dich deines eigenen Verstandes zu
- bedienen! ist also der Wahlspruch der Aufklärung.
- </chapter>
<bibliography>
<bibEntry>
- <name>Dezember-Heft</name>
+ <title>Dezember-Heft</title>
<journal>Berlinische Monatsschrift</journal>
<year>1784</year>
<pages>{481-494}</pages>
</bibEntry>
<bibEntry>
- <name>Kleine Schriften</name>
+ <title>Kleine Schriften</title>
<primaryAuthor>
<firstName>Immanuel</firstName>
<lastName>Kant</lastName>
@@ -62,7 +39,7 @@
<location>Neuwied</location>
</bibEntry>
<bibEntry>
- <name>Zerstreute Aufsätze</name>
+ <title>Zerstreute Aufsätze</title>
<primaryAuthor>
<firstName>Immanuel</firstName>
<lastName>Kant</lastName>
@@ -72,7 +49,7 @@
<location>Frankfurt und Leipzig</location>
</bibEntry>
<bibEntry>
- <name>Sämmtliche kleine Schriften</name>
+ <title>Sämmtliche kleine Schriften</title>
<primaryAuthor>
<firstName>Immanuel</firstName>
<lastName>Kant</lastName>
@@ -82,7 +59,7 @@
<location>Königsberg u. Leipzig</location>
</bibEntry>
<bibEntry>
- <name>I. Kant's vermischte Schriften</name>
+ <title>I. Kant's vermischte Schriften</title>
<primaryAuthor>
<firstName>Immanuel</firstName>
<lastName>Kant</lastName>
@@ -92,7 +69,7 @@
<location>Halle</location>
</bibEntry>
<bibEntry>
- <name>Vorzügliche kleine Schriften und Aufsätze</name>
+ <title>Vorzügliche kleine Schriften und Aufsätze</title>
<primaryAuthor>
<firstName>Immanuel</firstName>
<lastName>Kant</lastName>
@@ -102,5 +79,23 @@
<location>Leipzig</location>
</bibEntry>
</bibliography>
+
+ <heading>
+ Beantwortung der Frage: Was ist Aufklärung?
+ </heading>
+
+ <chapter name="content">
+ <heading>Was ist Aufklärung?</heading>
+
+ Aufklärung ist der Ausgang des Menschen aus seiner
+ selbstverschuldeten Unmündigkeit. Unmündigkeit ist
+ das Unvermögen, sich seines Verstandes ohne Leitung eines anderen zu
+ bedienen. Selbstverschuldet ist diese Unmündigkeit, wenn
+ die Ursache derselben nicht am Mangel des Verstandes, sondern der
+ Entschließung und des Mutes liegt, sich seiner ohne Leitung eines
+ andern zu bedienen.
+ Sapere aude! Habe Mut, dich deines eigenen Verstandes zu
+ bedienen! ist also der Wahlspruch der Aufklärung.
+ </chapter>
</book>
</document>
diff --git a/testdata/osxmlparser/email.osxml b/testdata/osxmlparser/email.osxml
deleted file mode 100644
index 325f89a..0000000
--- a/testdata/osxmlparser/email.osxml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" standalone="yes"?>
-<typesystem name="email">
- <struct name="email">
- <field name="local" type="string"/>
- <field name="domainName" type="string"/>
- <field name="domainSuffix" type="string"/>
- </struct>
-</typesystem>
diff --git a/testdata/osxmlparser/generic.osxml b/testdata/osxmlparser/generic.osxml
deleted file mode 100644
index 799ed41..0000000
--- a/testdata/osxmlparser/generic.osxml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" standalone="yes"?>
-<typesystem name="border">
- <import>./color.osxml</import>
-
- <enum name="border-style">
- <entry>none</entry>
- <entry>dotted</entry>
- <entry>dashed</entry>
- <entry>solid</entry>
- <entry>double</entry>
- <entry>groove</entry>
- <entry>ridge</entry>
- <entry>inset</entry>
- <entry>outset</entry>
- </enum>
-
- <constant name="zero" value="0" type="int" />
- <constant name="black" value="[zero, zero, zero]" type="color" />
-
- <struct name="border">
- <field name="style" type="border-style"/>
- <field name="color" type="color" default="black" />
- </struct>
-
- <constant name="beautifulBorder" type="border" value="[color=aquamarine,style=solid]" />
- <constant name="moreBeautifulBorder" type="border" value="[dotted, azure]" />
-</typesystem>
-<!--<domain name="color">
- <struct name="bla" cardinality="{1,2}" isa="blub"/>
- <struct name="blub" cardinality="{1-3,5,>7}">
- <fields>
- <field></field>
- <primitive type="bla"/>
- </fields>
- </struct>
-</domain>-->
-
diff --git a/testdata/osxmlparser/lists_domain.osxml b/testdata/osxmlparser/lists_domain.osxml
deleted file mode 100644
index cacb9cc..0000000
--- a/testdata/osxmlparser/lists_domain.osxml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0"?>
-<domain name="lists">
- <import rel="domain" src="book.osxml"/>
-
- <struct name="ul" isa="book.paragraph">
- <!-- Here we solve the problem of parents using the isa
- mechanism, because a list may occur whereever a paragraph
- may occur. However we do want to override the default field. -->
- <field>
- <childRef name="item"/>
- </field>
- </struct>
- <struct name="ol" isa="book.paragraph">
- <!-- Here we solve the problem of parents using the isa
- mechanism, because a list may occur whereever a paragraph
- may occur. However we do want to override the default field. -->
- <field>
- <childRef name="item"/>
- </field>
- </struct>
- <struct name="item">
- <field>
- <childRef name="book.paragaph"/>
- </field>
- </struct>
-</domain>
diff --git a/testdata/osxmlparser/meta_domain.osxml b/testdata/osxmlparser/meta_domain.osxml
deleted file mode 100644
index 52dffc5..0000000
--- a/testdata/osxmlparser/meta_domain.osxml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0"?>
-<domain name="meta">
-
- <import rel="typesystem" src="./affiliation.osxml"/>
- <import rel="typesystem" src="./email.osxml"/>
- <import rel="typesystem" src="./version.osxml"/>
- <import rel="domain" src="./book_domain.osxml"/>
-
- <struct name="meta" cardinality="{1}" transparent="true">
- <field name="authors">
- <childRef ref="author"/>
- <childRef ref="version"/>
- </field>
- <parentRef ref="book">
- <field name="meta" isSubtree="true" optional="true"/>
- </parentRef>
- <parentRef ref="chapter">
- <field name="meta" isSubtree="true" optional="true"/>
- </parentRef>
- <!-- One could also include "article" and other things here -->
- </struct>
- <!-- no explicit cardinality, because we might have multiple authors -->
- <struct name="author">
- <primitive isSubtree="true" name="firstName" type="string"/>
- <primitive isSubtree="true" name="lastName" type="string"/>
- <primitive isSubtree="true" name="email" type="email" optional="true"/>
- <primitive isSubtree="true" name="affiliation" type="affiliation" optional="true"/>
- </struct>
- <!-- but we need at least one primary author -->
- <struct name="primaryAuthor" cardinality="{>0}" isa="author"/>
- <!-- version intermediate struct -->
- <struct name="version" cardinality="{0-1}">
- <primitive type="version"/>
- </struct>
-</domain>
diff --git a/testdata/osxmlparser/test.osxml b/testdata/osxmlparser/test.osxml
deleted file mode 100644
index e492488..0000000
--- a/testdata/osxmlparser/test.osxml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" standalone="yes"?>
-<domain name="test">
-
- <import rel="domain" src="./book_domain.osxml"/>
- <import rel="typesystem" src="./color.osxml"/>
-
- <struct name="fancycolor">
-
- <primitive type="color"/>
-
- <parentRef ref="book.book">
- <fieldRef ref="$default"/>
- </parentRef>
- </struct>
-</domain>
diff --git a/testdata/osxmlparser/version.osxml b/testdata/osxmlparser/version.osxml
deleted file mode 100644
index 0d52736..0000000
--- a/testdata/osxmlparser/version.osxml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" standalone="yes"?>
-<typesystem name="version">
- <struct name="version">
- <field name="major" type="int"/>
- <field name="minor" type="int"/>
- <field name="patch" type="int"/>
- </struct>
-</typesystem>