src/OdsHandler.h
branchv_0
changeset 8 0ba80e9b711f
parent 2 3e73d4ae8b49
child 9 4c578ae8e68a
--- a/src/OdsHandler.h	Thu Dec 20 00:26:00 2018 +0100
+++ b/src/OdsHandler.h	Sun Jan 06 22:15:38 2019 +0100
@@ -29,27 +29,18 @@
 #include <relpipe/reader/TypeId.h>
 #include <relpipe/reader/handlers/RelationalReaderStringHandler.h>
 #include <relpipe/reader/handlers/AttributeMetadata.h>
+#include <relpipe/xmlwriter/XMLWriter.h>
 
 namespace relpipe {
 namespace out {
 namespace ods {
 
 using namespace relpipe::reader;
+using namespace relpipe::xmlwriter;
 
 class OdsHandler : public handlers::RelationalReaderStringHadler {
 private:
-	std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8
-
-	// TODO: refactor and move common XML functions to relpipe-lib-xml
-	const char* INDENT_1 = "\t";
-	const char* INDENT_2 = "\t\t";
-	const char* INDENT_3 = "\t\t\t";
-	const char* INDENT_4 = "\t\t\t\t";
-	const char* INDENT_5 = "\t\t\t\t\t";
-	const char* INDENT_6 = "\t\t\t\t\t\t";
-
-	std::ostream &output;
-
+	shared_ptr<XMLWriter> xmlWriter;
 	std::vector<TypeId> columnTypes;
 	std::vector<string_t> columnTypeCodes;
 	std::vector<string_t> columnNames;
@@ -57,60 +48,33 @@
 	integer_t columnCount = 0;
 	integer_t relationCount = 0;
 
-	// TODO: refactor and move common XML functions to relpipe-lib-xml
-
-	const std::string escapeXmlText(const string_t &value) {
-		std::wstringstream result;
-
-		for (auto & ch : value) {
-			switch (ch) {
-				case L'&': result << L"&amp;";
-					break;
-				case L'<': result << L"&lt;";
-					break;
-				case L'>': result << L"&gt;";
-					break;
-				case L'\'': result << L"&apos;"; // TODO: escape ' and " only in attributes
-					break;
-				case L'"': result << L"&quot;"; // TODO: escape ' and " only in attributes
-					break;
-				default: result << ch;
-			}
-		}
-
-		return convertor.to_bytes(result.str());
-	}
-
 public:
 
-	OdsHandler(std::ostream& output) : output(output) {
+	OdsHandler(std::ostream& output) : xmlWriter(new XMLWriter(output)) {
 	}
 
 	void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override {
-		// TODO: refactor and move common XML functions to relpipe-lib-xml
-
 		valueCount = 0;
 		columnCount = 0;
 
 		if (relationCount == 0) {
-			output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
-			output << "<office:document" << std::endl;
-			output << INDENT_1 << "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" << std::endl;
-			output << INDENT_1 << "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"" << std::endl;
-			output << INDENT_1 << "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"" << std::endl;
-			output << INDENT_1 << "office:mimetype=\"application/vnd.oasis.opendocument.spreadsheet\"" << std::endl;
-			output << INDENT_1 << "office:version=\"1.2\">" << std::endl;
+			xmlWriter->writeStartElement(L"office:document",{
+				L"xmlns:office", L"urn:oasis:names:tc:opendocument:xmlns:office:1.0",
+				L"xmlns:table", L"urn:oasis:names:tc:opendocument:xmlns:table:1.0",
+				L"xmlns:text", L"urn:oasis:names:tc:opendocument:xmlns:text:1.0",
+				L"office:mimetype", L"application/vnd.oasis.opendocument.spreadsheet",
+				L"office:version", L"1.2"
+			});
 
-			output << INDENT_1 << "<office:body>" << std::endl;
-			output << INDENT_2 << "<office:spreadsheet>" << std::endl;
-
+			xmlWriter->writeStartElement(L"office:body");
+			xmlWriter->writeStartElement(L"office:spreadsheet");
 		} else {
-			output << INDENT_4 << "</table:table-row>" << std::endl;
-			output << INDENT_3 << "</table:table>" << std::endl;
+			xmlWriter->writeEndElement();
+			xmlWriter->writeEndElement();
 		}
 		relationCount++;
 		// TODO: rename relations with same names
-		output << INDENT_3 << "<table:table table:name=\"" << escapeXmlText(name) << "\">" << std::endl;
+		xmlWriter->writeStartElement(L"table:table",{L"table:name", name});
 
 
 		columnCount = attributes.size();
@@ -118,44 +82,39 @@
 		columnTypeCodes.resize(columnCount);
 		columnNames.resize(columnCount);
 
-		output << INDENT_4 << "<table:table-row>" << std::endl;
+		xmlWriter->writeStartElement(L"table:table-row");
 		for (int i = 0; i < attributes.size(); i++) {
 			columnNames[i] = attributes[i].getAttributeName();
 			columnTypes[i] = attributes[i].getTypeId();
 			columnTypeCodes[i] = attributes[i].getTypeName();
 
-			output << INDENT_5 << "<table:table-cell>" << std::endl;
-			output << INDENT_6 << "<text:p>";
-			output << escapeXmlText(columnNames[i]);
-			output << "</text:p>" << std::endl;
-			output << INDENT_5 << "</table:table-cell>" << std::endl;
+			xmlWriter->writeStartElement(L"table:table-cell");
+			xmlWriter->writeTextElement(L"text:p",{}, columnNames[i]);
+			xmlWriter->writeEndElement();
 		}
-		output << INDENT_4 << "</table:table-row>" << std::endl;
+		xmlWriter->writeEndElement();
 
 	}
 
 	void attribute(const string_t& value) override {
 		integer_t i = valueCount % columnCount;
 
-		if (i == 0 && valueCount) output << INDENT_4 << "</table:table-row>" << std::endl;
-		if (i == 0) output << INDENT_4 << "<table:table-row>" << std::endl;
+		if (i == 0 && valueCount) xmlWriter->writeEndElement();
+		if (i == 0) xmlWriter->writeStartElement(L"table:table-row");
 
 		valueCount++;
 
-		output << INDENT_5 << "<table:table-cell>" << std::endl;
-		output << INDENT_6 << "<text:p>";
-		output << escapeXmlText(value);
-		output << "</text:p>" << std::endl;
-		output << INDENT_5 << "</table:table-cell>" << std::endl;
-
+		xmlWriter->writeStartElement(L"table:table-cell");
+		xmlWriter->writeTextElement(L"text:p",{}, value);
+		xmlWriter->writeEndElement();
 	}
 
 	void endOfPipe() {
-		if (valueCount) output << INDENT_4 << "</table:table-row>" << std::endl;
-		if (relationCount) output << INDENT_3 << "</table:table>" << std::endl;
-		output << INDENT_2 << "</office:spreadsheet>" << std::endl;
-		output << INDENT_1 << "</office:body>" << std::endl;
-		output << "</office:document>" << std::endl;
+		if (valueCount) xmlWriter->writeEndElement();
+		if (relationCount) xmlWriter->writeEndElement();
+		xmlWriter->writeEndElement();
+		xmlWriter->writeEndElement();
+		xmlWriter->writeEndElement();
 
 	}