--- a/src/XmlHandler.h Sun Sep 16 14:39:10 2018 +0200
+++ b/src/XmlHandler.h Sun Sep 16 18:12:31 2018 +0200
@@ -29,25 +29,30 @@
std::vector<TypeId> columnTypes;
std::vector<string_t> columnTypeCodes;
std::vector<string_t> columnNames;
- std::vector<integer_t> columnWidths;
- std::vector<string_t> values; // all values are saved here and processed at the end of the relation
+ integer_t valueCount = 0;
integer_t columnCount = 0;
+ integer_t relationCount = 0;
-
-
- const string_t escapeXmlText(const string_t &value, const char* color) {
+ const std::string escapeXmlText(const string_t &value) {
std::wstringstream result;
for (auto & ch : value) {
switch (ch) {
- // FIXME: xml escaping
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 result.str();
+ return convertor.to_bytes(result.str());
}
public:
@@ -56,27 +61,58 @@
}
void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override {
- output << convertor.to_bytes(name) << ": (XML)" << endl;
+ // 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>" << std::endl;
+ // TODO: xmlns
+ } else {
+ output << INDENT << INDENT << "</record>" << std::endl;
+ output << INDENT << "</relation>" << std::endl;
+ }
+ relationCount++;
+ output << INDENT << "<relation>" << std::endl;
+
+ output << INDENT << INDENT << "<name>" << escapeXmlText(name) << "</name>" << std::endl;
+
+
columnCount = attributes.size();
columnTypes.resize(columnCount);
columnTypeCodes.resize(columnCount);
columnNames.resize(columnCount);
- columnWidths.resize(columnCount, 0);
for (int i = 0; i < attributes.size(); i++) {
columnNames[i] = attributes[i].getAttributeName();
columnTypes[i] = attributes[i].getTypeId();
columnTypeCodes[i] = attributes[i].getTypeName();
}
+
+ // TODO: print attribute metadata
}
void attribute(const string_t& value) override {
- integer_t i = values.size() % columnCount;
- values.push_back(value);
- columnWidths[i] = max(columnWidths[i], value.length());
+ integer_t i = valueCount % columnCount;
+
+ if (i == 0 && valueCount) output << INDENT << INDENT << "</record>" << std::endl;
+ if (i == 0) output << INDENT << INDENT << "<record>" << std::endl;
+
+ valueCount++;
+
+ // TODO: print attribute metadata (optional)
+ output << INDENT << INDENT << INDENT << "<attribute>";
+ output << escapeXmlText(value);
+ output << "</attribute>" << std::endl;
+
}
void endOfPipe() {
-
+ if (valueCount) output << INDENT << INDENT << "</record>" << std::endl;
+ if (relationCount) output << INDENT << "</relation>" << std::endl;
+ output << "</pipe>" << std::endl;
+
}
};
--- a/src/relpipe-out-xml.cpp Sun Sep 16 14:39:10 2018 +0200
+++ b/src/relpipe-out-xml.cpp Sun Sep 16 18:12:31 2018 +0200
@@ -1,4 +1,5 @@
#include <cstdlib>
+#include <unistd.h>
#include <memory>
#include <relpipe/cli/CLI.h>
@@ -19,6 +20,11 @@
int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR;
try {
+
+ // TODO: color syntax highlighting if stdout is TTY:
+ // if (isatty(fileno(stdout))) std::cout << "color" << std::endl;
+ // else std::cout << "no-color" << std::endl;
+
std::shared_ptr<RelationalReader> reader(Factory::create(std::cin));
XmlHandler handler(std::cout);
reader->addHandler(&handler);