src/OdsHandler.h
branchv_0
changeset 8 0ba80e9b711f
parent 2 3e73d4ae8b49
child 9 4c578ae8e68a
equal deleted inserted replaced
7:b99b1debb00c 8:0ba80e9b711f
    27 
    27 
    28 #include <relpipe/reader/typedefs.h>
    28 #include <relpipe/reader/typedefs.h>
    29 #include <relpipe/reader/TypeId.h>
    29 #include <relpipe/reader/TypeId.h>
    30 #include <relpipe/reader/handlers/RelationalReaderStringHandler.h>
    30 #include <relpipe/reader/handlers/RelationalReaderStringHandler.h>
    31 #include <relpipe/reader/handlers/AttributeMetadata.h>
    31 #include <relpipe/reader/handlers/AttributeMetadata.h>
       
    32 #include <relpipe/xmlwriter/XMLWriter.h>
    32 
    33 
    33 namespace relpipe {
    34 namespace relpipe {
    34 namespace out {
    35 namespace out {
    35 namespace ods {
    36 namespace ods {
    36 
    37 
    37 using namespace relpipe::reader;
    38 using namespace relpipe::reader;
       
    39 using namespace relpipe::xmlwriter;
    38 
    40 
    39 class OdsHandler : public handlers::RelationalReaderStringHadler {
    41 class OdsHandler : public handlers::RelationalReaderStringHadler {
    40 private:
    42 private:
    41 	std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8
    43 	shared_ptr<XMLWriter> xmlWriter;
    42 
       
    43 	// TODO: refactor and move common XML functions to relpipe-lib-xml
       
    44 	const char* INDENT_1 = "\t";
       
    45 	const char* INDENT_2 = "\t\t";
       
    46 	const char* INDENT_3 = "\t\t\t";
       
    47 	const char* INDENT_4 = "\t\t\t\t";
       
    48 	const char* INDENT_5 = "\t\t\t\t\t";
       
    49 	const char* INDENT_6 = "\t\t\t\t\t\t";
       
    50 
       
    51 	std::ostream &output;
       
    52 
       
    53 	std::vector<TypeId> columnTypes;
    44 	std::vector<TypeId> columnTypes;
    54 	std::vector<string_t> columnTypeCodes;
    45 	std::vector<string_t> columnTypeCodes;
    55 	std::vector<string_t> columnNames;
    46 	std::vector<string_t> columnNames;
    56 	integer_t valueCount = 0;
    47 	integer_t valueCount = 0;
    57 	integer_t columnCount = 0;
    48 	integer_t columnCount = 0;
    58 	integer_t relationCount = 0;
    49 	integer_t relationCount = 0;
    59 
    50 
    60 	// TODO: refactor and move common XML functions to relpipe-lib-xml
       
    61 
       
    62 	const std::string escapeXmlText(const string_t &value) {
       
    63 		std::wstringstream result;
       
    64 
       
    65 		for (auto & ch : value) {
       
    66 			switch (ch) {
       
    67 				case L'&': result << L"&amp;";
       
    68 					break;
       
    69 				case L'<': result << L"&lt;";
       
    70 					break;
       
    71 				case L'>': result << L"&gt;";
       
    72 					break;
       
    73 				case L'\'': result << L"&apos;"; // TODO: escape ' and " only in attributes
       
    74 					break;
       
    75 				case L'"': result << L"&quot;"; // TODO: escape ' and " only in attributes
       
    76 					break;
       
    77 				default: result << ch;
       
    78 			}
       
    79 		}
       
    80 
       
    81 		return convertor.to_bytes(result.str());
       
    82 	}
       
    83 
       
    84 public:
    51 public:
    85 
    52 
    86 	OdsHandler(std::ostream& output) : output(output) {
    53 	OdsHandler(std::ostream& output) : xmlWriter(new XMLWriter(output)) {
    87 	}
    54 	}
    88 
    55 
    89 	void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override {
    56 	void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override {
    90 		// TODO: refactor and move common XML functions to relpipe-lib-xml
       
    91 
       
    92 		valueCount = 0;
    57 		valueCount = 0;
    93 		columnCount = 0;
    58 		columnCount = 0;
    94 
    59 
    95 		if (relationCount == 0) {
    60 		if (relationCount == 0) {
    96 			output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
    61 			xmlWriter->writeStartElement(L"office:document",{
    97 			output << "<office:document" << std::endl;
    62 				L"xmlns:office", L"urn:oasis:names:tc:opendocument:xmlns:office:1.0",
    98 			output << INDENT_1 << "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" << std::endl;
    63 				L"xmlns:table", L"urn:oasis:names:tc:opendocument:xmlns:table:1.0",
    99 			output << INDENT_1 << "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"" << std::endl;
    64 				L"xmlns:text", L"urn:oasis:names:tc:opendocument:xmlns:text:1.0",
   100 			output << INDENT_1 << "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"" << std::endl;
    65 				L"office:mimetype", L"application/vnd.oasis.opendocument.spreadsheet",
   101 			output << INDENT_1 << "office:mimetype=\"application/vnd.oasis.opendocument.spreadsheet\"" << std::endl;
    66 				L"office:version", L"1.2"
   102 			output << INDENT_1 << "office:version=\"1.2\">" << std::endl;
    67 			});
   103 
    68 
   104 			output << INDENT_1 << "<office:body>" << std::endl;
    69 			xmlWriter->writeStartElement(L"office:body");
   105 			output << INDENT_2 << "<office:spreadsheet>" << std::endl;
    70 			xmlWriter->writeStartElement(L"office:spreadsheet");
   106 
       
   107 		} else {
    71 		} else {
   108 			output << INDENT_4 << "</table:table-row>" << std::endl;
    72 			xmlWriter->writeEndElement();
   109 			output << INDENT_3 << "</table:table>" << std::endl;
    73 			xmlWriter->writeEndElement();
   110 		}
    74 		}
   111 		relationCount++;
    75 		relationCount++;
   112 		// TODO: rename relations with same names
    76 		// TODO: rename relations with same names
   113 		output << INDENT_3 << "<table:table table:name=\"" << escapeXmlText(name) << "\">" << std::endl;
    77 		xmlWriter->writeStartElement(L"table:table",{L"table:name", name});
   114 
    78 
   115 
    79 
   116 		columnCount = attributes.size();
    80 		columnCount = attributes.size();
   117 		columnTypes.resize(columnCount);
    81 		columnTypes.resize(columnCount);
   118 		columnTypeCodes.resize(columnCount);
    82 		columnTypeCodes.resize(columnCount);
   119 		columnNames.resize(columnCount);
    83 		columnNames.resize(columnCount);
   120 
    84 
   121 		output << INDENT_4 << "<table:table-row>" << std::endl;
    85 		xmlWriter->writeStartElement(L"table:table-row");
   122 		for (int i = 0; i < attributes.size(); i++) {
    86 		for (int i = 0; i < attributes.size(); i++) {
   123 			columnNames[i] = attributes[i].getAttributeName();
    87 			columnNames[i] = attributes[i].getAttributeName();
   124 			columnTypes[i] = attributes[i].getTypeId();
    88 			columnTypes[i] = attributes[i].getTypeId();
   125 			columnTypeCodes[i] = attributes[i].getTypeName();
    89 			columnTypeCodes[i] = attributes[i].getTypeName();
   126 
    90 
   127 			output << INDENT_5 << "<table:table-cell>" << std::endl;
    91 			xmlWriter->writeStartElement(L"table:table-cell");
   128 			output << INDENT_6 << "<text:p>";
    92 			xmlWriter->writeTextElement(L"text:p",{}, columnNames[i]);
   129 			output << escapeXmlText(columnNames[i]);
    93 			xmlWriter->writeEndElement();
   130 			output << "</text:p>" << std::endl;
       
   131 			output << INDENT_5 << "</table:table-cell>" << std::endl;
       
   132 		}
    94 		}
   133 		output << INDENT_4 << "</table:table-row>" << std::endl;
    95 		xmlWriter->writeEndElement();
   134 
    96 
   135 	}
    97 	}
   136 
    98 
   137 	void attribute(const string_t& value) override {
    99 	void attribute(const string_t& value) override {
   138 		integer_t i = valueCount % columnCount;
   100 		integer_t i = valueCount % columnCount;
   139 
   101 
   140 		if (i == 0 && valueCount) output << INDENT_4 << "</table:table-row>" << std::endl;
   102 		if (i == 0 && valueCount) xmlWriter->writeEndElement();
   141 		if (i == 0) output << INDENT_4 << "<table:table-row>" << std::endl;
   103 		if (i == 0) xmlWriter->writeStartElement(L"table:table-row");
   142 
   104 
   143 		valueCount++;
   105 		valueCount++;
   144 
   106 
   145 		output << INDENT_5 << "<table:table-cell>" << std::endl;
   107 		xmlWriter->writeStartElement(L"table:table-cell");
   146 		output << INDENT_6 << "<text:p>";
   108 		xmlWriter->writeTextElement(L"text:p",{}, value);
   147 		output << escapeXmlText(value);
   109 		xmlWriter->writeEndElement();
   148 		output << "</text:p>" << std::endl;
       
   149 		output << INDENT_5 << "</table:table-cell>" << std::endl;
       
   150 
       
   151 	}
   110 	}
   152 
   111 
   153 	void endOfPipe() {
   112 	void endOfPipe() {
   154 		if (valueCount) output << INDENT_4 << "</table:table-row>" << std::endl;
   113 		if (valueCount) xmlWriter->writeEndElement();
   155 		if (relationCount) output << INDENT_3 << "</table:table>" << std::endl;
   114 		if (relationCount) xmlWriter->writeEndElement();
   156 		output << INDENT_2 << "</office:spreadsheet>" << std::endl;
   115 		xmlWriter->writeEndElement();
   157 		output << INDENT_1 << "</office:body>" << std::endl;
   116 		xmlWriter->writeEndElement();
   158 		output << "</office:document>" << std::endl;
   117 		xmlWriter->writeEndElement();
   159 
   118 
   160 	}
   119 	}
   161 
   120 
   162 };
   121 };
   163 
   122