Loading...
Searching...
No Matches
SearchXML.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 * SearchXML.h
33 *
34 * Created on: Jun 24, 2012
35 * Author: mpeura
36 */
37
38
39
40#ifndef DRAIN_SEARCH_XML
41#define DRAIN_SEARCH_XML
42
43#include <ostream>
44
45#include <drain/Sprinter.h>
46#include <drain/util/Path.h>
47// #include <drain/FlexibleVariable.h>
48
49// #include "ClassXML.h"
50
51namespace drain {
52
53
54class SearchXML {
55
56public:
57
59 typedef drain::Path<std::string,'/'> path_t; // consider xml_path_t
60 typedef path_t::elem_t path_elem_t;
61
62 typedef std::list<path_t> path_list_t;
63
65
76 // This could also be in TreeXMLutilities
77 template <class V>
78 static
79 bool findById(const V & tree, const std::string & tag, typename V::path_t & result, const typename V::path_t & path = path_t());
80
82
92 // This could also be in TreeXMLutilities
93 template <class T>
94 static
95 bool findById(const T & tree, const std::string & tag, path_list_t & result, const path_t & path = path_t());
96
99 template <class T, class E>
100 static
101 bool findByTag(const T & tree, const E & tag, path_list_t & result, const path_t & path = path_t());
102
104 // This could also be in TreeXMLutilities
109 template <class T, class E>
110 static
111 bool findByTags(const T & tree, const std::set<E> & tags, path_list_t & result, const path_t & path = path_t());
112
114
120 template <class T, class C>
121 static
122 bool findByClass(const T & t, const C & cls, std::list<typename T::path_elem_t> & result);
123
125
130 //template <class V, class E>
131 template <class T, class C>
132 static inline
133 bool findByClass(const T & t, const C & cls, path_list_t & result, const path_t & path = path_t());
134
135
136 /*
137 template <class TR>
138 static
139 std::ostream & toStream(std::ostream & ostr, const TR & tree, const std::string & defaultTag="unnamed", int indent=0);
140 */
141
142};
143
144
145template <class T>
146bool SearchXML::findById(const T & t, const std::string & id, typename T::path_t & result, const typename T::path_t & path){
147
148 if (t->id == id){
149 result = path;
150 return true;
151 }
152
153 // Recursion
154 for (const auto & entry: t){
155 if (findById(entry.second, id, result, path_t(path, entry.first))){
156 return true;
157 }
158 }
159
160 return false;
161 //return !result.empty();
162}
163
164
165
166template <class T>
167bool SearchXML::findById(const T & t, const std::string & id, SearchXML::path_list_t & result, const path_t & path){
168
169 if (t->id == id){
170 result.push_back(path);
171 }
172
173 for (const auto & entry: t){
174 findById(entry.second, id, result, path_t(path, entry.first));
175 }
176
177 return !result.empty();
178}
179
183//template <class N>
184template <class T, class N>
185bool SearchXML::findByTag(const T & t, const N & tag, SearchXML::path_list_t & result, const path_t & path){
186
187 // const T & t = tree(path);
188
189 if (t->typeIs(tag)){
190 result.push_back(path);
191 }
192
193 for (const auto & entry: t){
194 findByTag(entry.second, tag, result, path_t(path, entry.first));
195 }
196
197 return !result.empty();
198
199}
200
204template <class T,class N>
205bool SearchXML::findByTags(const T & t, const std::set<N> & tags, SearchXML::path_list_t & result, const SearchXML::path_t & path){
206
207 // const T & t = tree(path);
208
209 //if (t->typeIs(tag)){
210 if (tags.count(t->getType()) > 0){
211 result.push_back(path);
212 }
213
214 for (const auto & entry: t){
215 findByTags(entry.second, tags, result, path_t(path, entry.first));
216 }
217
218 //return result;
219 return !result.empty();
220}
221
222
223
224template <class T, class C>
225bool SearchXML::findByClass(const T & t, const C & cls, SearchXML::path_list_t & result, const SearchXML::path_t & path){
226
227 // drain::Logger mout(__FILE__,__FUNCTION__);
228
229 if (t->classList.has(cls)){
230 result.push_back(path);
231 }
232
233 for (const auto & entry: t){
234 // mout.warn(t->get("name", "<name>"), "... continuing to: ", path_t(path, entry.first));
235 findByClass(entry.second, cls, result, path_t(path, entry.first));
236 }
237
238 return !result.empty();
239}
240
242template <class T, class C>
243bool SearchXML::findByClass(const T & t, const C & cls, std::list<typename T::path_elem_t> & result){
244
245 for (const auto & entry: t){
246 if (entry.second->hasClass(cls)){
247 result.push_back(entry.first);
248 }
249 }
250
251 return !result.empty();
252}
253
254/*
255template <class TR>
256std::ostream & SearchXML::toStream(std::ostream & ostr, const TR & tree, const std::string & defaultTag, int indent){
257
258 // TODO: delegate to XML node start/end function, maybe xmlNodeToStream ?
259
260 const typename TR::container_t & children = tree.getChildren();
261
262 // const XML & data = tree.data; // template type forcing
263 const typename TR::node_data_t & data = tree.data;
264
265 tag_display_mode mode = EMPTY_TAG;
266
267 if (data.isCText()){ // this can be true only at root, and rarely so...?
268 data.nodeToStream(ostr, mode);
269 ostr << "<!--TX-->";
270 return ostr;
271 }
272
273 if (!tree->ctext.empty()){
274 drain::Logger mout(__FILE__, __FUNCTION__);
275 mout.warn("Non-CTEXT-elem with ctext: <", tree->getTag(), " id='", tree->getId(), "' ...>, text='", tree->ctext, "'");
276 }
277
278 if (!children.empty()){
279 mode = OPENING_TAG;
280 }
281
282 if (tree->isExplicit()){ // explicit
283 mode = OPENING_TAG;
284 }
285
286 if (tree->isSingular()){ // <br/> <hr/>
287 mode = EMPTY_TAG;
288 }
289
290
291 // Indent
292 //std::fill_n(std::ostream_iterator<char>(ostr), 2*indent, ' ');
293 std::string fill(2*indent, ' ');
294 ostr << fill;
295 tree->nodeToStream(ostr, mode);
296
297 if (mode == EMPTY_TAG){
298 ostr << "<!--ET-->";
299 ostr << '\n';
300 return ostr;
301 }
302 else if (tree->isStyle()){
303 // https://www.w3.org/TR/xml/#sec-cdata-sect
304 // ostr << "<![CDATA[ \n";
305
306 if (!tree->ctext.empty()){
307 // TODO: indent
308 ostr << fill << tree->ctext << " /" << "* CTEXT? *" << "/" << '\n';
309 }
310
311 if (!tree->getAttributes().empty()){
312 drain::Logger mout(__FILE__,__FUNCTION__);
313 mout.warn("STYLE elem ", tree->getId()," contains attributes, probably meant as style: ", sprinter(tree->getAttributes()));
314 ostr << "\n\t /" << "* <!-- DISCARDED attribs ";
315 Sprinter::toStream(ostr, tree->getAttributes()); //, StyleXML::styleRecordLayout
316 ostr << " /--> *" << "/" << '\n';
317 }
318
319 if (!tree->style.empty()){
320 ostr << fill << "/ ** style obj ** /" << '\n';
321 for (const auto & attr: tree->style){
322 ostr << fill << " ";
323 Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
324 //attr.first << ':' attr.first << ':';
325 ostr << '\n';
326 }
327 // ostr << fill << "}\n";
328 // Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
329 // ostr << '\n';
330 }
331
332 ostr << '\n';
333 // ostr << fill << "<!-- elems /-->" << '\n';
334 ostr << fill << "/ * elems * /" << '\n';
335 for (const auto & entry: tree.getChildren()){
336 if (!entry.second->ctext.empty()){
337 //ostr << fill << "<!-- elem("<< entry.first << ") ctext /-->" << '\n';
338 ostr << fill << " " << entry.first << " {" << entry.second->ctext << "} / * CTEXT * / \n";
339 }
340 if (!entry.second->getAttributes().empty()){
341 //ostr << fill << "<!-- elem("<< entry.first << ") attribs /-->" << '\n';
342 ostr << fill << " " << entry.first << " {\n";
343 for (const auto & attr: entry.second->getAttributes()){
344 ostr << fill << " ";
345 ostr << attr.first << ':' << attr.second << ';';
346 ostr << '\n';
347 }
348 ostr << fill << " }\n";
349 ostr << '\n';
350 }
351 }
352 ostr << "\n"; // end CTEXT
353 // ostr << " ]]>\n"; // end CTEXT
354 // end STYLE defs
355 ostr << fill;
356
357 }
358 else {
359
360 // Detect if all the children are of type CTEXT, to be rendered in a single line.
361 // Note: potential re-parsing will probably detect them as a single CTEXT element.
362 bool ALL_CTEXT = !children.empty();
363
364 for (const auto & entry: children){
365 if (!entry.second->isCText()){
366 ALL_CTEXT = false;
367 break;
368 }
369 }
370
371 if (ALL_CTEXT){
372 ostr << "<!--ALL_CTEXT-->";
373 char sep=0;
374 for (const auto & entry: children){
375 if (sep){
376 ostr << sep;
377 }
378 else {
379 sep = ' '; // consider global setting?
380 }
381 ostr << entry.second->getText();
382 }
383 }
384 else {
385 // ostr << "<!-- RECURSION -->";
386 ostr << '\n';
388 for (const auto & entry: children){
389 toStream(ostr, entry.second, entry.first, indent+1); // Notice, no ++indent
390 // "implicit" newline
391 }
392 ostr << fill; // for CLOSING tag
393 }
394
395 }
396
397
398 tree->nodeToStream(ostr, CLOSING_TAG);
399 //ostr << fill;
400 ostr << '\n'; // Always after closing tag!
401
402 //if (tree.data.id >= 0)
403 // ostr << "<!-- " << tree.data.id << " /-->\n";
404
405 return ostr;
406}
407*/
408
409
410} // drain::
411
412#endif /* DRAIN_UTILS_XML */
413
Definition Path.h:112
Definition SearchXML.h:54
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 SearchXML.h:243
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 SearchXML.h:59
Definition DataSelector.cpp:1277