37 using namespace relpipe::reader; |
37 using namespace relpipe::reader; |
38 |
38 |
39 class OdsHandler : public handlers::RelationalReaderStringHadler { |
39 class OdsHandler : public handlers::RelationalReaderStringHadler { |
40 private: |
40 private: |
41 std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8 |
41 std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8 |
42 const char* INDENT = "\t"; |
42 |
|
43 // TODO: refactor and move common XML functions to relpipe-lib-xml |
|
44 const char* INDENT_1 = "\t"; |
|
45 const char* INDENT_2 = "\t\t"; |
|
46 const char* INDENT_3 = "\t\t\t"; |
|
47 const char* INDENT_4 = "\t\t\t\t"; |
|
48 const char* INDENT_5 = "\t\t\t\t\t"; |
|
49 const char* INDENT_6 = "\t\t\t\t\t\t"; |
43 |
50 |
44 std::ostream &output; |
51 std::ostream &output; |
45 |
52 |
46 std::vector<TypeId> columnTypes; |
53 std::vector<TypeId> columnTypes; |
47 std::vector<string_t> columnTypeCodes; |
54 std::vector<string_t> columnTypeCodes; |
48 std::vector<string_t> columnNames; |
55 std::vector<string_t> columnNames; |
49 integer_t valueCount = 0; |
56 integer_t valueCount = 0; |
50 integer_t columnCount = 0; |
57 integer_t columnCount = 0; |
51 integer_t relationCount = 0; |
58 integer_t relationCount = 0; |
|
59 |
|
60 // TODO: refactor and move common XML functions to relpipe-lib-xml |
52 |
61 |
53 const std::string escapeXmlText(const string_t &value) { |
62 const std::string escapeXmlText(const string_t &value) { |
54 std::wstringstream result; |
63 std::wstringstream result; |
55 |
64 |
56 for (auto & ch : value) { |
65 for (auto & ch : value) { |
83 valueCount = 0; |
92 valueCount = 0; |
84 columnCount = 0; |
93 columnCount = 0; |
85 |
94 |
86 if (relationCount == 0) { |
95 if (relationCount == 0) { |
87 output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; |
96 output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; |
88 output << "<pipe TODO=\"ods\">" << std::endl; |
97 output << "<office:document" << std::endl; |
89 // TODO: xmlns |
98 output << INDENT_1 << "xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" << std::endl; |
|
99 output << INDENT_1 << "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"" << std::endl; |
|
100 output << INDENT_1 << "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"" << std::endl; |
|
101 output << INDENT_1 << "office:mimetype=\"application/vnd.oasis.opendocument.spreadsheet\"" << std::endl; |
|
102 output << INDENT_1 << "office:version=\"1.2\">" << std::endl; |
|
103 |
|
104 output << INDENT_1 << "<office:body>" << std::endl; |
|
105 output << INDENT_2 << "<office:spreadsheet>" << std::endl; |
|
106 |
90 } else { |
107 } else { |
91 output << INDENT << INDENT << "</record>" << std::endl; |
108 output << INDENT_4 << "</table:table-row>" << std::endl; |
92 output << INDENT << "</relation>" << std::endl; |
109 output << INDENT_3 << "</table:table>" << std::endl; |
93 } |
110 } |
94 relationCount++; |
111 relationCount++; |
95 output << INDENT << "<relation>" << std::endl; |
112 // TODO: rename relations with same names |
96 |
113 output << INDENT_3 << "<table:table table:name=\"" << escapeXmlText(name) << "\">" << std::endl; |
97 output << INDENT << INDENT << "<name>" << escapeXmlText(name) << "</name>" << std::endl; |
|
98 |
114 |
99 |
115 |
100 columnCount = attributes.size(); |
116 columnCount = attributes.size(); |
101 columnTypes.resize(columnCount); |
117 columnTypes.resize(columnCount); |
102 columnTypeCodes.resize(columnCount); |
118 columnTypeCodes.resize(columnCount); |
103 columnNames.resize(columnCount); |
119 columnNames.resize(columnCount); |
|
120 |
|
121 output << INDENT_4 << "<table:table-row>" << std::endl; |
104 for (int i = 0; i < attributes.size(); i++) { |
122 for (int i = 0; i < attributes.size(); i++) { |
105 columnNames[i] = attributes[i].getAttributeName(); |
123 columnNames[i] = attributes[i].getAttributeName(); |
106 columnTypes[i] = attributes[i].getTypeId(); |
124 columnTypes[i] = attributes[i].getTypeId(); |
107 columnTypeCodes[i] = attributes[i].getTypeName(); |
125 columnTypeCodes[i] = attributes[i].getTypeName(); |
|
126 |
|
127 output << INDENT_5 << "<table:table-cell>" << std::endl; |
|
128 output << INDENT_6 << "<text:p>"; |
|
129 output << escapeXmlText(columnNames[i]); |
|
130 output << "</text:p>" << std::endl; |
|
131 output << INDENT_5 << "</table:table-cell>" << std::endl; |
108 } |
132 } |
109 |
133 output << INDENT_4 << "</table:table-row>" << std::endl; |
110 // TODO: print attribute metadata |
134 |
111 } |
135 } |
112 |
136 |
113 void attribute(const string_t& value) override { |
137 void attribute(const string_t& value) override { |
114 integer_t i = valueCount % columnCount; |
138 integer_t i = valueCount % columnCount; |
115 |
139 |
116 if (i == 0 && valueCount) output << INDENT << INDENT << "</record>" << std::endl; |
140 if (i == 0 && valueCount) output << INDENT_4 << "</table:table-row>" << std::endl; |
117 if (i == 0) output << INDENT << INDENT << "<record>" << std::endl; |
141 if (i == 0) output << INDENT_4 << "<table:table-row>" << std::endl; |
118 |
142 |
119 valueCount++; |
143 valueCount++; |
120 |
144 |
121 // TODO: print attribute metadata (optional) |
145 output << INDENT_5 << "<table:table-cell>" << std::endl; |
122 output << INDENT << INDENT << INDENT << "<attribute>"; |
146 output << INDENT_6 << "<text:p>"; |
123 output << escapeXmlText(value); |
147 output << escapeXmlText(value); |
124 output << "</attribute>" << std::endl; |
148 output << "</text:p>" << std::endl; |
|
149 output << INDENT_5 << "</table:table-cell>" << std::endl; |
125 |
150 |
126 } |
151 } |
127 |
152 |
128 void endOfPipe() { |
153 void endOfPipe() { |
129 if (valueCount) output << INDENT << INDENT << "</record>" << std::endl; |
154 if (valueCount) output << INDENT_4 << "</table:table-row>" << std::endl; |
130 if (relationCount) output << INDENT << "</relation>" << std::endl; |
155 if (relationCount) output << INDENT_3 << "</table:table>" << std::endl; |
131 output << "</pipe>" << std::endl; |
156 output << INDENT_2 << "</office:spreadsheet>" << std::endl; |
|
157 output << INDENT_1 << "</office:body>" << std::endl; |
|
158 output << "</office:document>" << std::endl; |
132 |
159 |
133 } |
160 } |
134 |
161 |
135 }; |
162 }; |
136 |
163 |