Loading...
Searching...
No Matches
TreeXML.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 * TreeXML.h
33 *
34 * Created on: Jun 24, 2012
35 * Author: mpeura
36 */
37
38
39
40#ifndef DRAIN_TREE_XML
41#define DRAIN_TREE_XML
42
43#include <ostream>
44
45#include "TreeUnordered.h"
46#include "XML.h"
47#include "UtilsXML.h"
48
49
50namespace drain {
51
52/*
53template <class T>
54class SuperGlue { // :public drain::NodeXML<Luokko> {
55
56};
57*/
58template <typename N>
60};
61
65template <class T=int>
66class NodeXML : public XML {
67
68public:
69
70 typedef T xml_tag_t;
71 typedef NodeXML<T> xml_node_t;
72 typedef drain::Path<std::string,'/'> path_t; // basically, also path_elem_t could be a template.
73 typedef UnorderedMultiTree<xml_node_t,false, path_t> xml_tree_t;
74
76
101 template <T ELEM>
102 class Elem; // {} ?
103
105 template <T ELEM>
106 friend class Elem;
107
108
110
114 /*
115 inline
116 NodeXML(const intval_t & t = intval_t(0)){
117 drain::StringTools::import(++nextID, id);
118 setType(t);
119 };
120 */
121 inline
123 drain::StringTools::import(++nextID, id);
124 // setType(t);
125 };
126
127 //
129
135 inline
136 NodeXML(const NodeXML & node){
137 drain::StringTools::import(++nextID, id);
138 // XML::xmlAssignNode(*this, node); // RISKY!? Should be called by the copy constructors of derived classes.
139 }
140
141 inline
142 ~NodeXML(){};
143
144
145 /*
146 template <class T2> // "final"
147 void setType(const T2 &t){ // DANGER, without cast?
148 type = static_cast<intval_t>(t); // (elem_t)
149 // handleType(static_cast<T>(t)); REMOVED 2025/09
150 // in derived classes, eg. drain::image::BaseGDAL
151 // warning: case value ‘...’ not in enumerated type
152 }
153
154 // Consider this later, for user-defined (not enumerated) tag types.
155 // virtual
156 // void setType(const std::string & type);
157
158
159 inline
160 const intval_t & getType() const {
161 return type;
162 };
163 */
164
165 inline
166 T getNativeType() const {
167 return static_cast<T>(type); // may fail! consider two-way conversion assert
168 };
169
170public:
171
172
173
177 virtual
178 const std::string & getTag() const {
179 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::EnumDict<T>::dict) << std::endl; // <<
180 return drain::EnumDict<T>::getDict().getKey((T)type, false);
181 }
182
186 static inline // needed?
187 const std::string & getTag(const T & type){
188 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::EnumDict<T>::dict) << std::endl; // <<
189 return drain::EnumDict<T>::getDict().getKey((T)type, false);
190 }
191
192
193 inline
194 void set(const NodeXML & node){
195 if (isUndefined()){
196 // Should make sense, and be safe. Esp. when exactly same node type, by templating
197 setType(node.getType());
198 }
199 else if (type == STYLE) {
200 drain::Logger mout(__FILE__, __FUNCTION__);
201 mout.suspicious("copying STYLE from node: ", node);
202 }
203 drain::SmartMapTools::setValues<map_t>(getAttributes(), node.getAttributes());
204 }
205
206 inline
207 void set(const intval_t & type){
208 setType(type);
209 }
210
211 inline
212 void set(const std::string & s){
213 setText(s);
214 }
215
216 inline
217 void set(const char *s){
218 set(std::string(s));
219 }
220
221 inline
222 void set(const drain::Castable & s){
223 setText(s);
224 }
225
226 /*
227 inline
228 void set(const std::initializer_list<Variable::init_pair_t > &l){
229 // TODO: redirect to set(key,value), for consistency
230 if (type == STYLE){
231 drain::SmartMapTools::setValues(style, l);
232 }
233 else {
234 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), l); // add new keys
235 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
236 }
237 }
238 */
239
240 inline
241 //void set(const std::initializer_list<std::pair<const char *,const char *> > & args){
242 void set(const std::initializer_list<std::pair<const char *,const Variable> > & args){
243 // TODO: redirect to set(key,value), for consistency?
244 if (type == STYLE){
245 drain::Logger mout(__FILE__, __FUNCTION__);
246 mout.deprecating("Setting attributes/style of a STYLE element.");
247 setStyle(args);
248 /*
249 for (const auto & entry: l){
250 style[entry.first] = entry.second;
251 }
252 */
253 // drain::SmartMapTools::setValues(style, l);
254 }
255 else {
256 for (const auto & entry: args){
257 getAttributes()[entry.first] = entry.second;
258 }
260 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
261 }
262 }
263
264 template <class V>
265 inline
266 void set(const std::map<std::string, V> & args){
267 // TODO: redirect to set(key,value), for consistency
268 if (type == STYLE){
269 drain::Logger mout(__FILE__, __FUNCTION__);
270 mout.deprecating("Setting attributes/style of a STYLE element: ", args);
271 //drain::SmartMapTools::setValues(style, args);
272 setStyle(args);
273 /*
274 for (const auto & entry: args){
275 style[entry.first] = entry.second;
276 }
277 */
278 }
279 else {
280 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), args); // add new keys
281 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
282 }
283 }
284
285
286 template <class V>
287 inline
288 void set(const std::string & key, const V & value){
289 if (type == STYLE){
290 // Modify collection directly
291 drain::Logger mout(__FILE__, __FUNCTION__);
292 mout.deprecating("Setting style as attributes of a STYLE element: ", key, ':', value);
293 setStyle(key, value);
294 }
295 else if (key == "style"){
296 drain::Logger mout(__FILE__, __FUNCTION__);
297 mout.obsolete("Setting style as attribute: \"style\"=", value);
298 }
299 else if (key == "class"){
300 // mout.warn<LOG_DEBUG>("class");
301 std::string cls;
302 drain::StringTools::import(value, cls);
303 addClass(cls);
304 }
305 else {
306 setAttribute(key, value);
307 }
308
309 }
310
311 inline
312 NodeXML & operator=(const NodeXML & node){
313 return XML::xmlAssignNode(*this, node);
314 }
315
316 // Check char *
317 inline
318 NodeXML & operator=(const xml_tag_t & x){ // needed? possibly with tree(int x) ?
319 //set(x);
320 setType(x);
321 return *this;
322 }
323
324 inline
325 NodeXML & operator=(const Castable &c){
326 setText(c);
327 return *this;
328 }
329
330
331 inline
332 NodeXML & operator=(const std::string &s){
333 setText(s);
334 return *this;
335 }
336
337 inline
338 NodeXML & operator=(const char *s){
339 setText(s);
340 return *this;
341 }
342
343 inline
344 NodeXML & operator=(const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
345 set(l);
346 return *this;
347 }
348
349
351 // std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const;
355 virtual
356 std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const override;
357
358
359 template <class V>
360 static inline
361 std::ostream & docToStream(std::ostream & ostr, const V & tree){
362 V::node_data_t::xml_node_t::docTypeToStream(ostr);
363 V::node_data_t::xml_node_t::toStream(ostr, tree);
364 // UtilsXML::toStream(ostr, tree);
365 return ostr;
366 }
367
368
370
382 static // virtual
383 inline
384 std::ostream & docTypeToStream(std::ostream &ostr){
385 ostr << "<?xml ";
386 for (const auto & entry: xmldoc_attribs){
387 xmlAttribToStream(ostr, entry.first, entry.second);
388 }
389 ostr << "?>";
390 ostr << '\n';
391 return ostr;
392 }
393
395 typedef std::map<xml_tag_t,xml_tag_t> xml_default_elem_map_t;
396 static const xml_default_elem_map_t xml_default_elems;
397
398protected:
399
401
404 //virtual
405 //void handleType(const T & type) = 0;
406 //void handleType() = 0;
407
408
409
410 /*
411 virtual inline
412 void handleType(const T & type){
413 std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? type=" << type << std::endl;
414
415
416 if ((int)type != 0){
417 drain::Logger(__FILE__, __FUNCTION__).reject("handleType( ", (int)type, " ) - this is available only as specialized, by inherited classed like SVG, HTML?");
418 }
419 // DANGER, without cast?
420 // std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? " << type << '=' << std::endl;
421 // std::cerr << __FILE__ << ':' << __FUNCTION__ << " dict: " << drain::sprinter(drain::EnumDict<T>::dict) << std::endl;
422 }
423 */
424
425
427 //typedef std::map<std::string,std::string> xmldoc_attrib_map_t;
428 typedef std::list<std::pair<std::string,std::string> > xmldoc_attrib_map_t;
429 static xmldoc_attrib_map_t xmldoc_attribs;
430
431
432};
433
434/*
435 Impossible. Cannot construct final object, for example members are not available for #link() .
436template <>
437inline
438void NodeXML<int>::handle Type(const int & type){
439 // DANGER, without cast?
440 std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? " << type << '=' << std::endl;
441 std::cerr << __FILE__ << ':' << __FUNCTION__ << " dict: " << drain::sprinter(drain::EnumDict<int,XML>::dict) << std::endl;
442}
443*/
444
445template <>
446inline
447const std::string & NodeXML<int>::getTag() const {
448 return drain::EnumDict<int,XML>::dict.getKey(this->type, false);
449}
450
451typedef NodeXML<>::xml_tree_t TreeXML;
452//typedef drain::UnorderedMultiTree<NodeXML<>,false, NodeXML<>::path_t> TreeXML;
453
454// NOTE: template will not match for subclasses of NodeXML<E> because default template will match any class exactly.
455template <class E, bool EX, class P>
456struct TypeName< drain::UnorderedMultiTree<NodeXML<E>,EX,P> > {
457
458 static const std::string & str(){
459 static const std::string name = drain::StringBuilder<>("TreeXML<", TypeName<E>::str(), ">");
460 return name;
461 }
462
463};
464
465/* This could be it, unless already defined...
466template <class N, bool EX, class P>
467inline
468drain::UnorderedMultiTree<N,EX,P> & drain::UnorderedMultiTree<N,EX,P>::addChild(const drain::UnorderedMultiTree<N,EX,P>::key_t & key){
469 return XML::xmlAddChild(*this, key);
470}
471*/
472
473/* doesnt work
474template <class E, bool EX, class P>
475inline
476drain::UnorderedMultiTree<NodeXML<E>,EX,P> & drain::UnorderedMultiTree<NodeXML<E>,EX,P>::addChild(const std::string & key){
477 return XML::xmlAddChild(*this, key);
478}
479*/
480
481/*
482template <class N, bool EX, class P>
483template <typename K> // for K (path elem arg)
484const typename drain::UnorderedMultiTree<N,EX,P>::key_t & drain::UnorderedMultiTree<N,EX,P>::getKey(const K & key){
485 return drain::EnumDict<K>::dict.getKey(key, false);
486}
487*/
488
489
490
491template <class N>
492std::ostream & NodeXML<N>::nodeToStream(std::ostream &ostr, tag_display_mode mode) const {
493
494
495 if (isCText()){
496 if (mode != CLOSING_TAG){ // or: OPENING
497 ostr << ctext; // << '(' << mode << ')'; // << " /-->\n";
498 }
499 return ostr;
500 }
501 else if (isComment()){
502 // Remember: a large subtree can be commented out
503 if (mode != CLOSING_TAG){
504 ostr << "<!--"; // << ctext; // << " /-->\n";
505 }
506 }
507 else {
508
509 if (mode==CLOSING_TAG){
510 ostr << "</";
511 }
512 else {
513 ostr << '<';
514 }
515
516 if (getTag().empty()){
517 drain::Logger(__FILE__, __FUNCTION__).unimplemented<LOG_ERR>("defaultTag for type=", getType(), " requested by for ID=", getId(), " attr=", getAttributes());
518
519 ostr << "defaultTag"; // << ' '; FIX! getDefaultTag?
520 }
521 else {
522 ostr << getTag(); // << ' ';
523 // TODO check GDAL XML
524 // if (!defaultTag.empty())
525 // attribToStream(ostr, "name", defaultTag);
526 }
527 }
528
529 if (mode != CLOSING_TAG){
530
531 if (typeIs(STYLE)){
532 // xmlAttribToStream(ostr, "data-mode", "experimental");
533 }
534 else { // if (!isCText())
535
536 specificAttributesToStream(ostr);
537
538 char sep=0;
539
540 // Iterate attributes - note: also for comment
541 for (const auto & key: getAttributes().getKeyList()){
542 std::string v = get(key, "");
543 // Skip empties (so Sprinter::toStream not applicable)
544 if (!v.empty()){
545 xmlAttribToStream(ostr, key, v);
546 sep=' ';
547 }
548 }
549
550 // Handle CSS style separately
551 if (!style.empty()){
552 if (sep)
553 ostr << sep;
554 ostr << "style=\"";
555 Sprinter::sequenceToStream(ostr, style, StyleXML::styleLineLayout);
556 ostr << '"'; // << ' ';
557 }
558
559 /*
560 if (!ctext.empty()){
561 ostr << " "; // debugging
562 }
563 */
564 }
565
566 }
567
568 // END
569 if (isComment()){
570 ostr << ' '; // prefix for free ctext
571 if (mode != OPENING_TAG){
572 // it is EMPTY_TAG or CLOSING TAG
573 ostr << "/-->"; // \n
574 }
575 // warn if has children? or comment them??
576 }
577 else if (mode==EMPTY_TAG){ // OR no ctext!
578 // close TAG
579 ostr << "/>"; // \n <- check newline - add before indent?
580 }
581 else {
582 ostr << ">";
583 }
584
585 return ostr;
586
587}
588
589
590template <class N>
591inline
592std::ostream & operator<<(std::ostream &ostr, const NodeXML<N> & node){
593 return node.nodeToStream(ostr);
594}
595
597
604template <>
606
607
608template <class E, bool EX, class P>
609std::ostream & operator<<(std::ostream &ostr, const UnorderedMultiTree<NodeXML<E>,EX,P> & tree){
610 // DOC def? TODO: preamble/prologToStream()
611 NodeXML<E>::docTypeToStream(ostr); // must be member, to support virtual?
612 NodeXML<E>::toStream(ostr, tree, "");
613 return ostr;
614}
615
616
617
618/*
619inline
620std::ostream & operator<<(std::ostream &ostr, const TreeXML & t){
621 // DOC def? TODO: preamble/prologToStream()
622 TreeXML::node_data_t::docTypeToStream(ostr); // must be member, to support virtual?
623 TreeXML::node_data_t::toStream(ostr, t, "");
624 return ostr;
625}
626*/
627
628
629
630
631} // drain::
632
633#endif /* TREEXML_H_ */
634
Definition Castable.h:76
Two-way mapping between strings and objects of template class T.
Definition Dictionary.h:63
Definition TreeXML.h:59
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:312
Logger & unimplemented(const TT &... args)
Feature to be done. Special type of Logger::note().
Definition Log.h:511
Logger & deprecating(const TT &... args)
Feature will be removed. Special type of Logger::note().
Definition Log.h:521
A "handle" for specialized element classes, i.e. with members like width , height or radius .
Definition TreeXML.h:102
Definition TreeXML.h:341
static std::ostream & docTypeToStream(std::ostream &ostr)
Write the XML definition beginning any XML document.
Definition TreeXML.h:384
virtual const std::string & getTag() const
Definition TreeXML.h:178
std::list< std::pair< std::string, std::string > > xmldoc_attrib_map_t
Internal function called after setType()
Definition TreeXML.h:428
virtual std::ostream & nodeToStream(std::ostream &ostr, tag_display_mode mode=EMPTY_TAG) const override
Dumps info. Future option: outputs leading and ending tag.
Definition TreeXML.h:492
static const std::string & getTag(const T &type)
Definition TreeXML.h:187
static std::ostream & docToStream(std::ostream &ostr, const V &tree)
Definition TreeXML.h:733
NodeXML & setText(const S &value)
Assign the text content of this node. If the node type is undefined, set it to CTEXT.
Definition TreeXML.h:619
std::map< xml_tag_t, xml_tag_t > xml_default_elem_map_t
Helps creating child elements. Like children of HTML element UL should be LI.
Definition TreeXML.h:395
NodeXML()
Default constructor.
Definition TreeXML.h:122
static std::ostream & toStream(std::ostream &ostr, const V &t, const std::string &defaultTag="", int indent=0)
"Forward definition" of Tree::toOstream
void set(const std::initializer_list< std::pair< const char *, const Variable > > &args)
Definition TreeXML.h:242
NodeXML(const NodeXML &node)
Copy constructor.
Definition TreeXML.h:136
Definition Path.h:112
static std::ostream & sequenceToStream(std::ostream &ostr, const T &x, const SprinterLayout &layout)
Convenience: if sequence type (array, list, set, map) not given, assume array.
Definition Sprinter.h:321
Definition StringBuilder.h:58
Base class for XML "nodes", to be data elements T for drain::Tree<T>
Definition TreeXML.h:80
void addClass(const TT &... args)
Style class.
Definition TreeXML.h:220
static void xmlAttribToStream(std::ostream &ostr, const std::string &key, const V &value)
Handy map for converting characters to XML entities. Example: '&' -> "&".
Definition XML.h:578
virtual void setAttribute(const std::string &key, const std::string &value)
Default implementation. Needed for handling units in strings, like "50%" or "640px".
Definition TreeXML.h:166
static N & xmlAssignNode(N &dst, const N &src)
Assign tree node (data) to another.
Definition XML.h:654
Definition DataSelector.cpp:1277
A container for a static dictionary of enumeration values.
Definition EnumFlags.h:69
static const std::string name
Default implementation: name returned by std::type_info::name()
Definition Type.h:558