--- a/src/XmlHandler.h Sat Jan 05 18:38:14 2019 +0100
+++ b/src/XmlHandler.h Sun Jan 06 22:15:38 2019 +0100
@@ -29,20 +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 xml {
using namespace relpipe::reader;
+using namespace relpipe::xmlwriter;
class XmlHandler : public handlers::RelationalReaderStringHadler {
private:
- std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8
- const char* INDENT = "\t";
-
- std::ostream &output;
-
+ shared_ptr<XMLWriter> xmlWriter;
std::vector<TypeId> columnTypes;
std::vector<string_t> columnTypeCodes;
std::vector<string_t> columnNames;
@@ -50,53 +48,25 @@
integer_t columnCount = 0;
integer_t relationCount = 0;
- const std::string escapeXmlText(const string_t &value) {
- // TODO: really bad performance → rewrite
- // 72 % of whole relpipe-out-xml according to valgrind/callgrind
- 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:
- XmlHandler(std::ostream& output) : output(output) {
+ XmlHandler(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 << "<pipe xmlns=\"tag:globalcode.info,2018:relpipe\">" << std::endl;
- // TODO: xmlns
+ xmlWriter->writeStartElement(L"pipe",{L"xmlns", L"tag:globalcode.info,2018:relpipe"});
} else {
- output << INDENT << INDENT << "</record>" << std::endl;
- output << INDENT << "</relation>" << std::endl;
+ xmlWriter->writeEndElement();
+ xmlWriter->writeEndElement();
}
relationCount++;
- output << INDENT << "<relation>" << std::endl;
+ xmlWriter->writeStartElement(L"relation");
- output << INDENT << INDENT << "<name>" << escapeXmlText(name) << "</name>" << std::endl;
+ xmlWriter->writeTextElement(L"name",{}, name);
columnCount = attributes.size();
@@ -108,30 +78,27 @@
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 << "</record>" << std::endl;
- if (i == 0) output << INDENT << INDENT << "<record>" << std::endl;
+ if (i == 0 && valueCount) xmlWriter->writeEndElement();
+ if (i == 0) xmlWriter->writeStartElement(L"record");
valueCount++;
// TODO: print attribute metadata (optional)
- output << INDENT << INDENT << INDENT << "<attribute>";
- output << escapeXmlText(value);
- output << "</attribute>" << std::endl;
+ xmlWriter->writeTextElement(L"attribute",{}, value);
}
void endOfPipe() {
- if (valueCount) output << INDENT << INDENT << "</record>" << std::endl;
- if (relationCount) output << INDENT << "</relation>" << std::endl;
- output << "</pipe>" << std::endl;
-
+ if (valueCount) xmlWriter->writeEndElement();
+ if (relationCount) xmlWriter->writeEndElement();
+ xmlWriter->writeEndElement();
}
};