# HG changeset patch # User František Kučera # Date 1607031063 -3600 # Node ID d68192f0e96095218e39ba272bddf1b8d75a918b # Parent 8d2d8f4077af96ccb8b1bfaa5f3b337933ceb48d convert YAML to relations Expected structure is: map: key = relation name value = sequence of maps (records) where: key = attribute name value = attribute value Example: -------- fruit: - id: 1 name: cherry - id: 2 name: apple - id: 3 name: plum empty: # this relation has no attributes and will be ignored sparse: - a: aaa b: bbb c: ccc - a: AAA b: BBB - c: C d: D e: E a: A f: F - c: CCC -------- Not yet supported: -------- my_relation_with_metadata: attribute-metadata: - name: a type: string - name: b type: boolean record: - a: a - b: true -------- diff -r 8d2d8f4077af -r d68192f0e960 src/YAMLCommand.h --- a/src/YAMLCommand.h Thu Dec 03 17:16:09 2020 +0100 +++ b/src/YAMLCommand.h Thu Dec 03 22:31:03 2020 +0100 @@ -32,7 +32,7 @@ class YAMLCommand { private: - std::wstring_convert> convertor; // TODO: support also other encodings. + std::wstring_convert> convertor; // YAML strings are in UTF-8 class YAMLEvent { private: @@ -98,20 +98,25 @@ using YAMLEvent_p = std::shared_ptr; - enum class Mode { - ROOT, - RELATIONS_SEQUENCE, - MAPPING, - MAP_KEY + enum class State { + START, + RELATIONS, + ATTRIBUTE, + RECORDS }; - std::vector mode; + State state; + + relpipe::writer::string_t y2s(yaml_char_t* value) { + return value ? convertor.from_bytes((const char*) value) : L""; + } - /** - * Both YAML and XML strings are in UTF-8. - */ - const char* y2x(yaml_char_t* value) { - return value ? (const char*) value : ""; + relpipe::writer::string_t findValue(std::vector record, relpipe::writer::string_t key) { + if (record.size() % 2) relpipe::writer::RelpipeWriterException(L"Invalid count of values in the record vector"); + for (size_t i = 0; i < record.size(); i += 2) { + if (record[i] == key) return record[i + 1]; + } + return L""; } public: @@ -125,32 +130,60 @@ void process(std::istream& input, std::shared_ptr writer) { parser.setInput(&input); + relpipe::writer::string_t relationName; + std::vector record; std::vector attributesMetadata; - attributesMetadata.push_back(relpipe::writer::AttributeMetadata{L"todo", relpipe::writer::TypeId::STRING}); - writer->startRelation(L"YAML", attributesMetadata, true); - mode.push_back(Mode::ROOT); - std::string itemName; - - writer->writeAttribute(L"before cycle"); - for (YAMLEvent_p event = YAMLEvent_p(parser.next()); event; event = YAMLEvent_p(parser.next())) { + state = State::START; - if (event->getType() == YAML_NO_EVENT) { writer->writeAttribute(L"YAML_NO_EVENT"); - } else if (event->getType() == YAML_STREAM_START_EVENT) { writer->writeAttribute(L"YAML_STREAM_START_EVENT"); - } else if (event->getType() == YAML_STREAM_END_EVENT) { writer->writeAttribute(L"YAML_STREAM_END_EVENT"); - } else if (event->getType() == YAML_DOCUMENT_START_EVENT) { writer->writeAttribute(L"YAML_DOCUMENT_START_EVENT"); - } else if (event->getType() == YAML_DOCUMENT_END_EVENT) { writer->writeAttribute(L"YAML_DOCUMENT_END_EVENT"); - } else if (event->getType() == YAML_ALIAS_EVENT) { writer->writeAttribute(L"YAML_ALIAS_EVENT"); - } else if (event->getType() == YAML_SCALAR_EVENT) { writer->writeAttribute(L"YAML_SCALAR_EVENT"); - } else if (event->getType() == YAML_SEQUENCE_START_EVENT) { writer->writeAttribute(L"YAML_SEQUENCE_START_EVENT"); - } else if (event->getType() == YAML_SEQUENCE_END_EVENT) { writer->writeAttribute(L"YAML_SEQUENCE_END_EVENT"); - } else if (event->getType() == YAML_MAPPING_START_EVENT) { writer->writeAttribute(L"YAML_MAPPING_START_EVENT"); - } else if (event->getType() == YAML_MAPPING_END_EVENT) { writer->writeAttribute(L"YAML_MAPPING_END_EVENT"); - } else { writer->writeAttribute(L"else???"); - // TODO: unsupported type? + for (YAMLEvent_p event = YAMLEvent_p(parser.next()); event; event = YAMLEvent_p(parser.next())) { + if (event->getType() == YAML_NO_EVENT) { + throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: YAML_NO_EVENT"); + } else if (event->getType() == YAML_STREAM_START_EVENT) { + } else if (event->getType() == YAML_STREAM_END_EVENT) { + } else if (event->getType() == YAML_DOCUMENT_START_EVENT) { + } else if (event->getType() == YAML_DOCUMENT_END_EVENT) { + } else if (event->getType() == YAML_ALIAS_EVENT) { + } else if (event->getType() == YAML_SCALAR_EVENT) { + relpipe::writer::string_t scalarValue = y2s(event->getEvent()->data.scalar.value); + if (state == State::RELATIONS) relationName = scalarValue; + else if (state == State::ATTRIBUTE) record.push_back(scalarValue); + else throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_SCALAR_EVENT"); + } else if (event->getType() == YAML_SEQUENCE_START_EVENT) { + if (state == State::RELATIONS) state = State::RECORDS; + else throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_SEQUENCE_START_EVENT"); + } else if (event->getType() == YAML_SEQUENCE_END_EVENT) { + if (state == State::RECORDS) { + state = State::RELATIONS; + relationName.clear(); + attributesMetadata.clear(); + } else { + throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_SEQUENCE_END_EVENT"); + } + } else if (event->getType() == YAML_MAPPING_START_EVENT) { + if (state == State::START) state = State::RELATIONS; + else if (state == State::RECORDS) state = State::ATTRIBUTE; + else if (state == State::RELATIONS) throw relpipe::writer::RelpipeWriterException(L"Not yet implemented"); // TODO: there might be also a map in the relation value (not only a sequence) that would contain metadata (i.e. data types + support for relation containing no records) + else throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_MAPPING_START_EVENT"); + } else if (event->getType() == YAML_MAPPING_END_EVENT) { + if (state == State::ATTRIBUTE) { + if (attributesMetadata.size() == 0) { + if (record.size() % 2) relpipe::writer::RelpipeWriterException(L"Invalid count of values in the record vector"); + for (size_t i = 0; i < record.size(); i += 2) attributesMetadata.push_back(relpipe::writer::AttributeMetadata{record[i], relpipe::writer::TypeId::STRING}); + writer->startRelation(relationName, attributesMetadata, true); + } + for (auto m : attributesMetadata) writer->writeAttribute(findValue(record, m.attributeName)); + record.clear(); + state = State::RECORDS; + } else if (state == State::RELATIONS) { + break; // map of the relations ends (root) + } else { + throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_MAPPING_END_EVENT"); + } + } else { + throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unknown event: " + std::to_wstring(event->getType())); } } - writer->writeAttribute(L"after cycle"); } };