27 std::ostream &output; |
27 std::ostream &output; |
28 |
28 |
29 std::vector<TypeId> columnTypes; |
29 std::vector<TypeId> columnTypes; |
30 std::vector<string_t> columnTypeCodes; |
30 std::vector<string_t> columnTypeCodes; |
31 std::vector<string_t> columnNames; |
31 std::vector<string_t> columnNames; |
32 std::vector<integer_t> columnWidths; |
32 integer_t valueCount = 0; |
33 std::vector<string_t> values; // all values are saved here and processed at the end of the relation |
|
34 integer_t columnCount = 0; |
33 integer_t columnCount = 0; |
|
34 integer_t relationCount = 0; |
35 |
35 |
36 |
36 const std::string escapeXmlText(const string_t &value) { |
37 |
|
38 const string_t escapeXmlText(const string_t &value, const char* color) { |
|
39 std::wstringstream result; |
37 std::wstringstream result; |
40 |
38 |
41 for (auto & ch : value) { |
39 for (auto & ch : value) { |
42 switch (ch) { |
40 switch (ch) { |
43 // FIXME: xml escaping |
|
44 case L'&': result << L"&"; |
41 case L'&': result << L"&"; |
|
42 break; |
|
43 case L'<': result << L"<"; |
|
44 break; |
|
45 case L'>': result << L">"; |
|
46 break; |
|
47 case L'\'': result << L"'"; // TODO: escape ' and " only in attributes |
|
48 break; |
|
49 case L'"': result << L"""; // TODO: escape ' and " only in attributes |
45 break; |
50 break; |
46 default: result << ch; |
51 default: result << ch; |
47 } |
52 } |
48 } |
53 } |
49 |
54 |
50 return result.str(); |
55 return convertor.to_bytes(result.str()); |
51 } |
56 } |
52 |
57 |
53 public: |
58 public: |
54 |
59 |
55 XmlHandler(std::ostream& output) : output(output) { |
60 XmlHandler(std::ostream& output) : output(output) { |
56 } |
61 } |
57 |
62 |
58 void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override { |
63 void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override { |
59 output << convertor.to_bytes(name) << ": (XML)" << endl; |
64 // TODO: refactor and move common XML functions to relpipe-lib-xml |
|
65 |
|
66 valueCount = 0; |
|
67 columnCount = 0; |
|
68 |
|
69 if (relationCount == 0) { |
|
70 output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; |
|
71 output << "<pipe>" << std::endl; |
|
72 // TODO: xmlns |
|
73 } else { |
|
74 output << INDENT << INDENT << "</record>" << std::endl; |
|
75 output << INDENT << "</relation>" << std::endl; |
|
76 } |
|
77 relationCount++; |
|
78 output << INDENT << "<relation>" << std::endl; |
|
79 |
|
80 output << INDENT << INDENT << "<name>" << escapeXmlText(name) << "</name>" << std::endl; |
|
81 |
|
82 |
60 columnCount = attributes.size(); |
83 columnCount = attributes.size(); |
61 columnTypes.resize(columnCount); |
84 columnTypes.resize(columnCount); |
62 columnTypeCodes.resize(columnCount); |
85 columnTypeCodes.resize(columnCount); |
63 columnNames.resize(columnCount); |
86 columnNames.resize(columnCount); |
64 columnWidths.resize(columnCount, 0); |
|
65 for (int i = 0; i < attributes.size(); i++) { |
87 for (int i = 0; i < attributes.size(); i++) { |
66 columnNames[i] = attributes[i].getAttributeName(); |
88 columnNames[i] = attributes[i].getAttributeName(); |
67 columnTypes[i] = attributes[i].getTypeId(); |
89 columnTypes[i] = attributes[i].getTypeId(); |
68 columnTypeCodes[i] = attributes[i].getTypeName(); |
90 columnTypeCodes[i] = attributes[i].getTypeName(); |
69 } |
91 } |
|
92 |
|
93 // TODO: print attribute metadata |
70 } |
94 } |
71 |
95 |
72 void attribute(const string_t& value) override { |
96 void attribute(const string_t& value) override { |
73 integer_t i = values.size() % columnCount; |
97 integer_t i = valueCount % columnCount; |
74 values.push_back(value); |
98 |
75 columnWidths[i] = max(columnWidths[i], value.length()); |
99 if (i == 0 && valueCount) output << INDENT << INDENT << "</record>" << std::endl; |
|
100 if (i == 0) output << INDENT << INDENT << "<record>" << std::endl; |
|
101 |
|
102 valueCount++; |
|
103 |
|
104 // TODO: print attribute metadata (optional) |
|
105 output << INDENT << INDENT << INDENT << "<attribute>"; |
|
106 output << escapeXmlText(value); |
|
107 output << "</attribute>" << std::endl; |
|
108 |
76 } |
109 } |
77 |
110 |
78 void endOfPipe() { |
111 void endOfPipe() { |
79 |
112 if (valueCount) output << INDENT << INDENT << "</record>" << std::endl; |
|
113 if (relationCount) output << INDENT << "</relation>" << std::endl; |
|
114 output << "</pipe>" << std::endl; |
|
115 |
80 } |
116 } |
81 |
117 |
82 }; |
118 }; |
83 |
119 |
84 } |
120 } |