diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-02-18 21:29:36 +0100 |
---|---|---|
committer | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-02-18 21:29:36 +0100 |
commit | 5dfa2b6cba3e31d18e2cc23f05d330e387fc1a29 (patch) | |
tree | 2f97711bd12bfdb35425c0ffaca5af6a231b8076 /src | |
parent | f6d3495b681e19227a5ea9ec081d36644be55d68 (diff) | |
parent | 19e3e43e80e413d297ca8970d018eeda57ee65e1 (diff) |
Merge branch 'master' of somweyr.de:ousia
Diffstat (limited to 'src')
-rw-r--r-- | src/core/common/VariantConverter.cpp | 4 | ||||
-rw-r--r-- | src/core/common/VariantWriter.cpp | 31 | ||||
-rw-r--r-- | src/core/common/VariantWriter.hpp | 22 | ||||
-rw-r--r-- | src/core/model/Domain.cpp | 37 | ||||
-rw-r--r-- | src/core/model/Domain.hpp | 1 | ||||
-rw-r--r-- | src/core/parser/ParserScope.cpp | 12 | ||||
-rw-r--r-- | src/core/parser/ParserScope.hpp | 18 | ||||
-rw-r--r-- | src/core/parser/stack/DocumentHandler.cpp | 74 | ||||
-rw-r--r-- | src/core/parser/stack/DomainHandler.cpp | 16 | ||||
-rw-r--r-- | src/core/parser/stack/Stack.cpp | 20 | ||||
-rw-r--r-- | src/core/parser/stack/TypesystemHandler.cpp | 20 | ||||
-rw-r--r-- | src/formats/osxml/OsxmlEventParser.cpp | 6 | ||||
-rw-r--r-- | src/plugins/xml/XmlOutput.cpp | 66 | ||||
-rw-r--r-- | src/plugins/xml/XmlOutput.hpp | 2 |
14 files changed, 241 insertions, 88 deletions
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> ¤t, + 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> ¤t, + 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); |