Loading...
Searching...
No Matches
UtilsXML.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25 */
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31/*
32 * UtilsXML.h
33 *
34 * Created on: Jun 24, 2012
35 * Author: mpeura
36 */
37
38
39
40#ifndef DRAIN_UTILS_XML
41#define DRAIN_UTILS_XML
42
43#include <ostream>
44
45#include <drain/Sprinter.h>
46// #include <drain/FlexibleVariable.h>
47
48// #include "ClassXML.h"
49
50namespace drain {
51
52
53class UtilsXML {
54
55public:
56
58 typedef drain::Path<std::string,'/'> path_t; // consider xml_path_t
59 typedef path_t::elem_t path_elem_t;
60
61 typedef std::list<path_t> path_list_t;
62
64
75 // This could also be in TreeXMLutilities
76 template <class V>
77 static
78 bool findById(const V & tree, const std::string & tag, typename V::path_t & result, const typename V::path_t & path = path_t());
79
81
91 // This could also be in TreeXMLutilities
92 template <class T>
93 static
94 bool findById(const T & tree, const std::string & tag, path_list_t & result, const path_t & path = path_t());
95
98 template <class T, class E>
99 static
100 bool findByTag(const T & tree, const E & tag, path_list_t & result, const path_t & path = path_t());
101
103 // This could also be in TreeXMLutilities
108 template <class T, class E>
109 static
110 bool findByTags(const T & tree, const std::set<E> & tags, path_list_t & result, const path_t & path = path_t());
111
113
119 template <class T, class C>
120 static
121 bool findByClass(const T & t, const C & cls, std::list<typename T::path_elem_t> & result);
122
124
129 //template <class V, class E>
130 template <class T, class C>
131 static inline
132 bool findByClass(const T & t, const C & cls, path_list_t & result, const path_t & path = path_t());
133
134
135 /*
136 template <class TR>
137 static
138 std::ostream & toStream(std::ostream & ostr, const TR & tree, const std::string & defaultTag="unnamed", int indent=0);
139 */
140
141};
142
143
144template <class T>
145bool UtilsXML::findById(const T & t, const std::string & id, typename T::path_t & result, const typename T::path_t & path){
146
147 if (t->id == id){
148 result = path;
149 return true;
150 }
151
152 // Recursion
153 for (const auto & entry: t){
154 if (findById(entry.second, id, result, path_t(path, entry.first))){
155 return true;
156 }
157 }
158
159 return false;
160 //return !result.empty();
161}
162
163
164
165template <class T>
166bool UtilsXML::findById(const T & t, const std::string & id, UtilsXML::path_list_t & result, const path_t & path){
167
168 if (t->id == id){
169 result.push_back(path);
170 }
171
172 for (const auto & entry: t){
173 findById(entry.second, id, result, path_t(path, entry.first));
174 }
175
176 return !result.empty();
177}
178
182//template <class N>
183template <class T, class N>
184bool UtilsXML::findByTag(const T & t, const N & tag, UtilsXML::path_list_t & result, const path_t & path){
185
186 // const T & t = tree(path);
187
188 if (t->typeIs(tag)){
189 result.push_back(path);
190 }
191
192 for (const auto & entry: t){
193 findByTag(entry.second, tag, result, path_t(path, entry.first));
194 }
195
196 return !result.empty();
197
198}
199
203template <class T,class N>
204bool UtilsXML::findByTags(const T & t, const std::set<N> & tags, UtilsXML::path_list_t & result, const UtilsXML::path_t & path){
205
206 // const T & t = tree(path);
207
208 //if (t->typeIs(tag)){
209 if (tags.count(t->getType()) > 0){
210 result.push_back(path);
211 }
212
213 for (const auto & entry: t){
214 findByTags(entry.second, tags, result, path_t(path, entry.first));
215 }
216
217 //return result;
218 return !result.empty();
219}
220
221
222
223template <class T, class C>
224bool UtilsXML::findByClass(const T & t, const C & cls, UtilsXML::path_list_t & result, const UtilsXML::path_t & path){
225
226 // drain::Logger mout(__FILE__,__FUNCTION__);
227
228 if (t->classList.has(cls)){
229 result.push_back(path);
230 }
231
232 for (const auto & entry: t){
233 // mout.warn(t->get("name", "<name>"), "... continuing to: ", path_t(path, entry.first));
234 findByClass(entry.second, cls, result, path_t(path, entry.first));
235 }
236
237 return !result.empty();
238}
239
241template <class T, class C>
242bool UtilsXML::findByClass(const T & t, const C & cls, std::list<typename T::path_elem_t> & result){
243
244 for (const auto & entry: t){
245 if (entry.second->hasClass(cls)){
246 result.push_back(entry.first);
247 }
248 }
249
250 return !result.empty();
251}
252
253/*
254template <class TR>
255std::ostream & UtilsXML::toStream(std::ostream & ostr, const TR & tree, const std::string & defaultTag, int indent){
256
257 // TODO: delegate to XML node start/end function, maybe xmlNodeToStream ?
258
259 const typename TR::container_t & children = tree.getChildren();
260
261 // const XML & data = tree.data; // template type forcing
262 const typename TR::node_data_t & data = tree.data;
263
264 tag_display_mode mode = EMPTY_TAG;
265
266 if (data.isCText()){ // this can be true only at root, and rarely so...?
267 data.nodeToStream(ostr, mode);
268 ostr << "<!--TX-->";
269 return ostr;
270 }
271
272 if (!tree->ctext.empty()){
273 drain::Logger mout(__FILE__, __FUNCTION__);
274 mout.warn("Non-CTEXT-elem with ctext: <", tree->getTag(), " id='", tree->getId(), "' ...>, text='", tree->ctext, "'");
275 }
276
277 if (!children.empty()){
278 mode = OPENING_TAG;
279 }
280
281 if (tree->isExplicit()){ // explicit
282 mode = OPENING_TAG;
283 }
284
285 if (tree->isSingular()){ // <br/> <hr/>
286 mode = EMPTY_TAG;
287 }
288
289
290 // Indent
291 //std::fill_n(std::ostream_iterator<char>(ostr), 2*indent, ' ');
292 std::string fill(2*indent, ' ');
293 ostr << fill;
294 tree->nodeToStream(ostr, mode);
295
296 if (mode == EMPTY_TAG){
297 ostr << "<!--ET-->";
298 ostr << '\n';
299 return ostr;
300 }
301 else if (tree->isStyle()){
302 // https://www.w3.org/TR/xml/#sec-cdata-sect
303 // ostr << "<![CDATA[ \n";
304
305 if (!tree->ctext.empty()){
306 // TODO: indent
307 ostr << fill << tree->ctext << " /" << "* CTEXT? *" << "/" << '\n';
308 }
309
310 if (!tree->getAttributes().empty()){
311 drain::Logger mout(__FILE__,__FUNCTION__);
312 mout.warn("STYLE elem ", tree->getId()," contains attributes, probably meant as style: ", sprinter(tree->getAttributes()));
313 ostr << "\n\t /" << "* <!-- DISCARDED attribs ";
314 Sprinter::toStream(ostr, tree->getAttributes()); //, StyleXML::styleRecordLayout
315 ostr << " /--> *" << "/" << '\n';
316 }
317
318 if (!tree->style.empty()){
319 ostr << fill << "/ ** style obj ** /" << '\n';
320 for (const auto & attr: tree->style){
321 ostr << fill << " ";
322 Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
323 //attr.first << ':' attr.first << ':';
324 ostr << '\n';
325 }
326 // ostr << fill << "}\n";
327 // Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
328 // ostr << '\n';
329 }
330
331 ostr << '\n';
332 // ostr << fill << "<!-- elems /-->" << '\n';
333 ostr << fill << "/ * elems * /" << '\n';
334 for (const auto & entry: tree.getChildren()){
335 if (!entry.second->ctext.empty()){
336 //ostr << fill << "<!-- elem("<< entry.first << ") ctext /-->" << '\n';
337 ostr << fill << " " << entry.first << " {" << entry.second->ctext << "} / * CTEXT * / \n";
338 }
339 if (!entry.second->getAttributes().empty()){
340 //ostr << fill << "<!-- elem("<< entry.first << ") attribs /-->" << '\n';
341 ostr << fill << " " << entry.first << " {\n";
342 for (const auto & attr: entry.second->getAttributes()){
343 ostr << fill << " ";
344 ostr << attr.first << ':' << attr.second << ';';
345 ostr << '\n';
346 }
347 ostr << fill << " }\n";
348 ostr << '\n';
349 }
350 }
351 ostr << "\n"; // end CTEXT
352 // ostr << " ]]>\n"; // end CTEXT
353 // end STYLE defs
354 ostr << fill;
355
356 }
357 else {
358
359 // Detect if all the children are of type CTEXT, to be rendered in a single line.
360 // Note: potential re-parsing will probably detect them as a single CTEXT element.
361 bool ALL_CTEXT = !children.empty();
362
363 for (const auto & entry: children){
364 if (!entry.second->isCText()){
365 ALL_CTEXT = false;
366 break;
367 }
368 }
369
370 if (ALL_CTEXT){
371 ostr << "<!--ALL_CTEXT-->";
372 char sep=0;
373 for (const auto & entry: children){
374 if (sep){
375 ostr << sep;
376 }
377 else {
378 sep = ' '; // consider global setting?
379 }
380 ostr << entry.second->getText();
381 }
382 }
383 else {
384 // ostr << "<!-- RECURSION -->";
385 ostr << '\n';
387 for (const auto & entry: children){
388 toStream(ostr, entry.second, entry.first, indent+1); // Notice, no ++indent
389 // "implicit" newline
390 }
391 ostr << fill; // for CLOSING tag
392 }
393
394 }
395
396
397 tree->nodeToStream(ostr, CLOSING_TAG);
398 //ostr << fill;
399 ostr << '\n'; // Always after closing tag!
400
401 //if (tree.data.id >= 0)
402 // ostr << "<!-- " << tree.data.id << " /-->\n";
403
404 return ostr;
405}
406*/
407
408
409} // drain::
410
411#endif /* DRAIN_UTILS_XML */
412
Definition Path.h:112
Definition UtilsXML.h:53
static bool findByTag(const T &tree, const E &tag, path_list_t &result, const path_t &path=path_t())
static bool findByClass(const T &t, const C &cls, std::list< typename T::path_elem_t > &result)
Finds child elements in an XML structure by class name.
Definition UtilsXML.h:242
static bool findByTags(const T &tree, const std::set< E > &tags, path_list_t &result, const path_t &path=path_t())
"Forward definition"
static bool findById(const V &tree, const std::string &tag, typename V::path_t &result, const typename V::path_t &path=path_t())
Find the first occurrence of given id using recursive breath-first search.
drain::Path< std::string,'/'> path_t
Tree path type. // TODO: extract from template.
Definition UtilsXML.h:58
Definition DataSelector.cpp:1277