diff -r 000000000000 -r 2f3c9e508827 src/OdsHandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/OdsHandler.h Fri Dec 07 12:49:39 2018 +0100 @@ -0,0 +1,139 @@ +/** + * Relational pipes + * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace relpipe { +namespace out { +namespace ods { + +using namespace relpipe::reader; + +class OdsHandler : public handlers::RelationalReaderStringHadler { +private: + std::wstring_convert> convertor; // XML output will be always in UTF-8 + const char* INDENT = "\t"; + + std::ostream &output; + + std::vector columnTypes; + std::vector columnTypeCodes; + std::vector columnNames; + integer_t valueCount = 0; + integer_t columnCount = 0; + integer_t relationCount = 0; + + const std::string escapeXmlText(const string_t &value) { + std::wstringstream result; + + for (auto & ch : value) { + switch (ch) { + case L'&': result << L"&"; + break; + case L'<': result << L"<"; + break; + case L'>': result << L">"; + break; + case L'\'': result << L"'"; // TODO: escape ' and " only in attributes + break; + case L'"': result << L"""; // TODO: escape ' and " only in attributes + break; + default: result << ch; + } + } + + return convertor.to_bytes(result.str()); + } + +public: + + OdsHandler(std::ostream& output) : output(output) { + } + + void startRelation(string_t name, std::vector attributes) override { + // TODO: refactor and move common XML functions to relpipe-lib-xml + + valueCount = 0; + columnCount = 0; + + if (relationCount == 0) { + output << "" << std::endl; + output << "" << std::endl; + // TODO: xmlns + } else { + output << INDENT << INDENT << "" << std::endl; + output << INDENT << "" << std::endl; + } + relationCount++; + output << INDENT << "" << std::endl; + + output << INDENT << INDENT << "" << escapeXmlText(name) << "" << std::endl; + + + columnCount = attributes.size(); + columnTypes.resize(columnCount); + columnTypeCodes.resize(columnCount); + columnNames.resize(columnCount); + for (int i = 0; i < attributes.size(); i++) { + columnNames[i] = attributes[i].getAttributeName(); + columnTypes[i] = attributes[i].getTypeId(); + columnTypeCodes[i] = attributes[i].getTypeName(); + } + + // TODO: print attribute metadata + } + + void attribute(const string_t& value) override { + integer_t i = valueCount % columnCount; + + if (i == 0 && valueCount) output << INDENT << INDENT << "" << std::endl; + if (i == 0) output << INDENT << INDENT << "" << std::endl; + + valueCount++; + + // TODO: print attribute metadata (optional) + output << INDENT << INDENT << INDENT << ""; + output << escapeXmlText(value); + output << "" << std::endl; + + } + + void endOfPipe() { + if (valueCount) output << INDENT << INDENT << "" << std::endl; + if (relationCount) output << INDENT << "" << std::endl; + output << "" << std::endl; + + } + +}; + +} +} +}