--- a/nbproject/configurations.xml Thu Dec 20 00:26:00 2018 +0100
+++ b/nbproject/configurations.xml Sun Jan 06 22:15:38 2019 +0100
@@ -80,6 +80,7 @@
<incDir>
<pElem>../relpipe-lib-reader.cpp/include</pElem>
<pElem>../relpipe-lib-cli.cpp/include</pElem>
+ <pElem>../relpipe-lib-xmlwriter.cpp/include</pElem>
<pElem>build/Debug/src</pElem>
</incDir>
</ccTool>
--- a/src/CMakeLists.txt Thu Dec 20 00:26:00 2018 +0100
+++ b/src/CMakeLists.txt Sun Jan 06 22:15:38 2019 +0100
@@ -18,7 +18,7 @@
# Relpipe libraries:
INCLUDE(FindPkgConfig)
-pkg_check_modules (RELPIPE_LIBS relpipe-lib-reader.cpp relpipe-lib-cli.cpp)
+pkg_check_modules (RELPIPE_LIBS relpipe-lib-reader.cpp relpipe-lib-cli.cpp relpipe-lib-xmlwriter.cpp)
include_directories(${RELPIPE_LIBS_INCLUDE_DIRS})
link_directories(${RELPIPE_LIBS_LIBRARY_DIRS})
--- 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"&";
- 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) {
+ 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();
}
--- a/src/relpipe-out-ods.cpp Thu Dec 20 00:26:00 2018 +0100
+++ b/src/relpipe-out-ods.cpp Sun Jan 06 22:15:38 2019 +0100
@@ -24,12 +24,14 @@
#include <relpipe/reader/Factory.h>
#include <relpipe/reader/RelationalReader.h>
#include <relpipe/reader/RelpipeReaderException.h>
+#include <relpipe/xmlwriter/XMLWriter.h>
#include "OdsHandler.h"
using namespace relpipe::cli;
using namespace relpipe::reader;
using namespace relpipe::out::ods;
+using namespace relpipe::xmlwriter;
int main(int argc, char** argv) {
setlocale(LC_ALL, "");
@@ -57,6 +59,9 @@
fwprintf(stderr, L"Caught Reader exception: %ls\n", e.getMessge().c_str());
fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount());
resultCode = CLI::EXIT_CODE_DATA_ERROR;
+ } catch (RelpipeXMLWriterException e) {
+ fwprintf(stderr, L"Error while writing XML: %ls\n", e.getMessge().c_str());
+ resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR;
}
return resultCode;