src/XmlHandler.h
branchv_0
changeset 13 816094aa1fff
parent 12 b8274181b061
child 14 5094a7bf343d
equal deleted inserted replaced
12:b8274181b061 13:816094aa1fff
    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 xml {
    36 namespace xml {
    36 
    37 
    37 using namespace relpipe::reader;
    38 using namespace relpipe::reader;
       
    39 using namespace relpipe::xmlwriter;
    38 
    40 
    39 class XmlHandler : public handlers::RelationalReaderStringHadler {
    41 class XmlHandler : 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 	const char* INDENT = "\t";
       
    43 
       
    44 	std::ostream &output;
       
    45 
       
    46 	std::vector<TypeId> columnTypes;
    44 	std::vector<TypeId> columnTypes;
    47 	std::vector<string_t> columnTypeCodes;
    45 	std::vector<string_t> columnTypeCodes;
    48 	std::vector<string_t> columnNames;
    46 	std::vector<string_t> columnNames;
    49 	integer_t valueCount = 0;
    47 	integer_t valueCount = 0;
    50 	integer_t columnCount = 0;
    48 	integer_t columnCount = 0;
    51 	integer_t relationCount = 0;
    49 	integer_t relationCount = 0;
    52 
    50 
    53 	const std::string escapeXmlText(const string_t &value) {
       
    54 		// TODO: really bad performance → rewrite
       
    55 		// 72 % of whole relpipe-out-xml according to valgrind/callgrind
       
    56 		std::wstringstream result;
       
    57 
       
    58 		for (auto & ch : value) {
       
    59 			switch (ch) {
       
    60 				case L'&': result << L"&amp;";
       
    61 					break;
       
    62 				case L'<': result << L"&lt;";
       
    63 					break;
       
    64 				case L'>': result << L"&gt;";
       
    65 					break;
       
    66 				case L'\'': result << L"&apos;"; // TODO: escape ' and " only in attributes
       
    67 					break;
       
    68 				case L'"': result << L"&quot;"; // TODO: escape ' and " only in attributes
       
    69 					break;
       
    70 				default: result << ch;
       
    71 			}
       
    72 		}
       
    73 
       
    74 		return convertor.to_bytes(result.str());
       
    75 	}
       
    76 
       
    77 public:
    51 public:
    78 
    52 
    79 	XmlHandler(std::ostream& output) : output(output) {
    53 	XmlHandler(std::ostream& output) : xmlWriter(new XMLWriter(output)) {
    80 	}
    54 	}
    81 
    55 
    82 	void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override {
    56 	void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override {
    83 		// TODO: refactor and move common XML functions to relpipe-lib-xml
       
    84 
       
    85 		valueCount = 0;
    57 		valueCount = 0;
    86 		columnCount = 0;
    58 		columnCount = 0;
    87 
    59 
    88 		if (relationCount == 0) {
    60 		if (relationCount == 0) {
    89 			output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
    61 			xmlWriter->writeStartElement(L"pipe",{L"xmlns", L"tag:globalcode.info,2018:relpipe"});
    90 			output << "<pipe xmlns=\"tag:globalcode.info,2018:relpipe\">" << std::endl;
       
    91 			// TODO: xmlns
       
    92 		} else {
    62 		} else {
    93 			output << INDENT << INDENT << "</record>" << std::endl;
    63 			xmlWriter->writeEndElement();
    94 			output << INDENT << "</relation>" << std::endl;
    64 			xmlWriter->writeEndElement();
    95 		}
    65 		}
    96 		relationCount++;
    66 		relationCount++;
    97 		output << INDENT << "<relation>" << std::endl;
    67 		xmlWriter->writeStartElement(L"relation");
    98 
    68 
    99 		output << INDENT << INDENT << "<name>" << escapeXmlText(name) << "</name>" << std::endl;
    69 		xmlWriter->writeTextElement(L"name",{}, name);
   100 
    70 
   101 
    71 
   102 		columnCount = attributes.size();
    72 		columnCount = attributes.size();
   103 		columnTypes.resize(columnCount);
    73 		columnTypes.resize(columnCount);
   104 		columnTypeCodes.resize(columnCount);
    74 		columnTypeCodes.resize(columnCount);
   106 		for (int i = 0; i < attributes.size(); i++) {
    76 		for (int i = 0; i < attributes.size(); i++) {
   107 			columnNames[i] = attributes[i].getAttributeName();
    77 			columnNames[i] = attributes[i].getAttributeName();
   108 			columnTypes[i] = attributes[i].getTypeId();
    78 			columnTypes[i] = attributes[i].getTypeId();
   109 			columnTypeCodes[i] = attributes[i].getTypeName();
    79 			columnTypeCodes[i] = attributes[i].getTypeName();
   110 		}
    80 		}
   111 		
    81 
   112 		// TODO: print attribute metadata
    82 		// TODO: print attribute metadata
   113 	}
    83 	}
   114 
    84 
   115 	void attribute(const string_t& value) override {
    85 	void attribute(const string_t& value) override {
   116 		integer_t i = valueCount % columnCount;
    86 		integer_t i = valueCount % columnCount;
   117 
    87 
   118 		if (i == 0 && valueCount) output << INDENT << INDENT << "</record>" << std::endl;
    88 		if (i == 0 && valueCount) xmlWriter->writeEndElement();
   119 		if (i == 0) output << INDENT << INDENT << "<record>" << std::endl;
    89 		if (i == 0) xmlWriter->writeStartElement(L"record");
   120 
    90 
   121 		valueCount++;
    91 		valueCount++;
   122 
    92 
   123 		// TODO: print attribute metadata (optional)
    93 		// TODO: print attribute metadata (optional)
   124 		output << INDENT << INDENT << INDENT << "<attribute>";
    94 		xmlWriter->writeTextElement(L"attribute",{}, value);
   125 		output << escapeXmlText(value);
       
   126 		output << "</attribute>" << std::endl;
       
   127 
    95 
   128 	}
    96 	}
   129 
    97 
   130 	void endOfPipe() {
    98 	void endOfPipe() {
   131 		if (valueCount) output << INDENT << INDENT << "</record>" << std::endl;
    99 		if (valueCount) xmlWriter->writeEndElement();
   132 		if (relationCount) output << INDENT << "</relation>" << std::endl;
   100 		if (relationCount) xmlWriter->writeEndElement();
   133 		output << "</pipe>" << std::endl;
   101 		xmlWriter->writeEndElement();
   134 
       
   135 	}
   102 	}
   136 
   103 
   137 };
   104 };
   138 
   105 
   139 }
   106 }