51 const char* INDENT = "\t"; |
51 const char* INDENT = "\t"; |
52 |
52 |
53 ostream& output; |
53 ostream& output; |
54 wstring_convert<codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8 |
54 wstring_convert<codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8 |
55 vector<wstring> treePosition; |
55 vector<wstring> treePosition; |
|
56 bool lastWasTextNode = false; |
56 |
57 |
57 const string escapeXmlText(const wstring& value) { |
58 const string escapeXmlText(const wstring& value) { |
58 // TODO: really bad performance → rewrite |
59 // TODO: really bad performance → rewrite |
59 // 72 % of whole relpipe-out-xml according to valgrind/callgrind |
60 // 72 % of whole relpipe-out-xml according to valgrind/callgrind |
60 // Moved here from XmlHandler.h (relpipe-out-xml). |
61 // Moved here from XmlHandler.h (relpipe-out-xml). |
112 checkName(name); |
113 checkName(name); |
113 output << " " << convertor.to_bytes(name) << "=\"" << escapeXmlAttribute(value) << "\""; |
114 output << " " << convertor.to_bytes(name) << "=\"" << escapeXmlAttribute(value) << "\""; |
114 } |
115 } |
115 } |
116 } |
116 |
117 |
|
118 void writeIndentation(bool resetState = true) { |
|
119 if (lastWasTextNode) { |
|
120 if (resetState) lastWasTextNode = false; |
|
121 } else { |
|
122 output << endl; |
|
123 for (int i = 0; i < treePosition.size(); i++) { |
|
124 output << INDENT; |
|
125 } |
|
126 } |
|
127 } |
|
128 |
117 public: |
129 public: |
118 |
130 |
119 XMLWriter(std::ostream& output) : output(output) { |
131 XMLWriter(std::ostream& output) : output(output) { |
120 output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; |
132 output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; |
121 } |
133 } |
122 |
134 |
123 virtual ~XMLWriter() { |
135 virtual ~XMLWriter() { |
|
136 output << endl; |
124 output.flush(); |
137 output.flush(); |
125 } |
138 } |
126 |
139 |
127 void writeStartElement(const wstring& name, const vector<wstring>& attributes = {}) { |
140 void writeStartElement(const wstring& name, const vector<wstring>& attributes = {}) { |
128 // FIXME: indentation |
|
129 checkName(name); |
141 checkName(name); |
|
142 writeIndentation(); |
130 treePosition.push_back(name); |
143 treePosition.push_back(name); |
131 output << "<" << convertor.to_bytes(name); |
144 output << "<" << convertor.to_bytes(name); |
132 writeAttributes(attributes); |
145 writeAttributes(attributes); |
133 output << ">"; |
146 output << ">"; |
134 } |
147 } |
135 |
148 |
136 void writeEndElement() { |
149 void writeEndElement() { |
137 // FIXME: indentation |
|
138 if (treePosition.empty()) throw RelpipeXMLWriterException(L"unable to close element – all elements are already closed"); |
150 if (treePosition.empty()) throw RelpipeXMLWriterException(L"unable to close element – all elements are already closed"); |
139 output << "</" << convertor.to_bytes(treePosition.back()) << ">"; |
151 wstring name = treePosition.back(); |
140 treePosition.pop_back(); |
152 treePosition.pop_back(); |
|
153 writeIndentation(); |
|
154 output << "</" << convertor.to_bytes(name) << ">"; |
141 } |
155 } |
142 |
156 |
143 void writeEmptyElement(const wstring& name, const vector<wstring>& attributes = {}) { |
157 void writeEmptyElement(const wstring& name, const vector<wstring>& attributes = {}) { |
144 // FIXME: indentation |
|
145 checkName(name); |
158 checkName(name); |
|
159 writeIndentation(); |
146 output << "<" << convertor.to_bytes(name); |
160 output << "<" << convertor.to_bytes(name); |
147 writeAttributes(attributes); |
161 writeAttributes(attributes); |
148 output << "/>"; |
162 output << "/>"; |
149 |
163 |
150 } |
164 } |
155 writeEndElement(); |
169 writeEndElement(); |
156 } |
170 } |
157 |
171 |
158 void writeCharacters(const wstring& text) { |
172 void writeCharacters(const wstring& text) { |
159 output << escapeXmlText(text); |
173 output << escapeXmlText(text); |
|
174 lastWasTextNode = true; |
160 } |
175 } |
161 |
176 |
162 void writeComment(const wstring& text, bool addSpaces = true) { |
177 void writeComment(const wstring& text, bool addSpaces = true) { |
163 output << addSpaces ? "<!-- " : "<!--"; |
178 writeIndentation(false); |
|
179 output << (addSpaces ? "<!-- " : "<!--"); |
164 output << escapeComment(text); |
180 output << escapeComment(text); |
165 output << addSpaces ? " -->" : "-->"; |
181 output << (addSpaces ? " -->" : "-->"); |
166 } |
182 } |
167 |
183 |
168 }; |
184 }; |
169 |
185 |
170 } |
186 } |