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
55template <class T=int>
56class NodeXML : public XML {
57
58public:
59
60 typedef T xml_tag_t;
61 typedef NodeXML<T> xml_node_t;
62 typedef drain::Path<std::string,'/'> path_t; // basically, also path_elem_t could be a template.
63 typedef UnorderedMultiTree<xml_node_t,false, path_t> xml_tree_t;
64
66
91 template <T ELEM>
92 class Elem; // {} ?
93
95 template <T ELEM>
96 friend class Elem;
97
98
100
104 /*
105 inline
106 NodeXML(const intval_t & t = intval_t(0)){
107 drain::StringTools::import(++nextID, id);
108 setType(t);
109 };
110 */
111 inline
113 drain::StringTools::import(++nextID, id);
114 // setType(t);
115 };
116
117 //
119
125 inline
126 NodeXML(const NodeXML & node){
127 drain::StringTools::import(++nextID, id);
128 // XML::xmlAssignNode(*this, node); // RISKY!? Should be called by the copy constructors of derived classes.
129 }
130
131 inline
132 ~NodeXML(){};
133
134 virtual
135 void swap(NodeXML<T> & node);
136
137 /*
138 template <class T2> // "final"
139 void setType(const T2 &t){ // DANGER, without cast?
140 type = static_cast<intval_t>(t); // (elem_t)
141 // handleType(static_cast<T>(t)); REMOVED 2025/09
142 // in derived classes, eg. drain::image::BaseGDAL
143 // warning: case value ‘...’ not in enumerated type
144 }
145
146 // Consider this later, for user-defined (not enumerated) tag types.
147 // virtual
148 // void setType(const std::string & type);
149
150
151 inline
152 const intval_t & getType() const {
153 return type;
154 };
155 */
156
157 inline
158 T getNativeType() const {
159 return static_cast<T>(type); // may fail! consider two-way conversion assert
160 };
161
162public:
163
164 inline
165 void set(const NodeXML & node){
166 if (isUndefined()){
167 // Should make sense, and be safe. Esp. when exactly same node type, by templating
168 setType(node.getType());
169 }
170 else if (type == STYLE) {
171 drain::Logger mout(__FILE__, __FUNCTION__);
172 mout.suspicious("copying STYLE from node: ", node);
173 }
174 drain::MapTools::setValues<map_t>(getAttributes(), node.getAttributes());
175 }
176
177
178 inline
179 void set(const intval_t & type){
180 setType(type);
181 }
182
183
184 inline
185 void set(const std::string & s){
186 setText(s);
187 }
188
189 inline
190 void set(const char *s){
191 set(std::string(s));
192 }
193
194 inline
195 void set(const drain::Castable & s){
196 setText(s);
197 }
198
199
200 inline
201 //void set(const std::initializer_list<std::pair<const char *,const char *> > & args){
202 void set(const std::initializer_list<std::pair<const char *,const Variable> > & args){
203 // TODO: redirect to set(key,value), for consistency?
204 if (type == STYLE){
205 drain::Logger mout(__FILE__, __FUNCTION__);
206 mout.deprecating("Setting attributes/style of a STYLE element.");
207 setStyle(args);
208 /*
209 for (const auto & entry: l){
210 style[entry.first] = entry.second;
211 }
212 */
213 // drain::SmartMapTools::setValues(style, l);
214 }
215 else {
216 for (const auto & entry: args){
217 getAttributes()[entry.first] = entry.second;
218 }
220 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
221 }
222 }
223
224 template <class V>
225 inline
226 void set(const std::map<std::string, V> & args){
227 // TODO: redirect to set(key,value), for consistency
228 if (type == STYLE){
229 drain::Logger mout(__FILE__, __FUNCTION__);
230 mout.deprecating("Setting attributes/style of a STYLE element: ", args);
231 //drain::SmartMapTools::setValues(style, args);
232 setStyle(args);
233 /*
234 for (const auto & entry: args){
235 style[entry.first] = entry.second;
236 }
237 */
238 }
239 else {
240 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), args); // add new keys
241 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
242 }
243 }
244
245
246 template <class V>
247 inline
248 void set(const std::string & key, const V & value){
249 if (type == STYLE){
250 // Modify collection directly
251 drain::Logger mout(__FILE__, __FUNCTION__);
252 mout.deprecating("Setting style as attributes of a STYLE element: ", key, ':', value);
253 setStyle(key, value);
254 }
255 else if (key == "style"){
256 drain::Logger mout(__FILE__, __FUNCTION__);
257 mout.obsolete("Setting style as attribute: \"style\"=", value);
258 }
259 else if (key == "class"){
260 // mout.warn<LOG_DEBUG>("class");
261 std::string cls;
262 drain::StringTools::import(value, cls);
263 addClass(cls);
264 }
265 else {
266 setAttribute(key, value);
267 }
268
269 }
270
271
275 virtual
276 const std::string & getTag() const {
277 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::EnumDict<T>::dict) << std::endl; // <<
278 return drain::EnumDict<T>::getDict().getKey((T)type, false);
279 }
280
284 static inline // needed?
285 const std::string & getTag(const T & type){
286 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::EnumDict<T>::dict) << std::endl; // <<
287 return drain::EnumDict<T>::getDict().getKey((T)type, false);
288 }
289
290
291
292 inline
293 NodeXML & operator=(const NodeXML & node){
294 return XML::xmlAssignNode(*this, node);
295 }
296
297 // Check char *
298 inline
299 NodeXML & operator=(const xml_tag_t & x){ // needed? possibly with tree(int x) ?
300 //set(x);
301 setType(x);
302 return *this;
303 }
304
305 inline
306 NodeXML & operator=(const Castable &c){
307 setText(c);
308 return *this;
309 }
310
311
312 inline
313 NodeXML & operator=(const std::string &s){
314 setText(s);
315 return *this;
316 }
317
318 inline
319 NodeXML & operator=(const char *s){
320 setText(s);
321 return *this;
322 }
323
324 inline
325 NodeXML & operator=(const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
326 set(l);
327 return *this;
328 }
329
330
332 // std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const;
336 virtual
337 std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const override;
338
339
340 template <class V>
341 static inline
342 std::ostream & docToStream(std::ostream & ostr, const V & tree){
343 V::node_data_t::xml_node_t::docTypeToStream(ostr);
344 V::node_data_t::xml_node_t::toStream(ostr, tree);
345 // UtilsXML::toStream(ostr, tree);
346 return ostr;
347 }
348
349
351
363 static // virtual
364 inline
365 std::ostream & docTypeToStream(std::ostream &ostr){
366 ostr << "<?xml ";
367 for (const auto & entry: xmldoc_attribs){
368 xmlAttribToStream(ostr, entry.first, entry.second);
369 }
370 ostr << "?>";
371 ostr << '\n';
372 return ostr;
373 }
374
376 typedef std::map<xml_tag_t,xml_tag_t> xml_default_elem_map_t;
377 static const xml_default_elem_map_t xml_default_elems;
378
379protected:
380
382
385 //virtual
386 //void handleType(const T & type) = 0;
387 //void handleType() = 0;
388
389
390
391 /*
392 virtual inline
393 void handleType(const T & type){
394 std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? type=" << type << std::endl;
395
396
397 if ((int)type != 0){
398 drain::Logger(__FILE__, __FUNCTION__).reject("handleType( ", (int)type, " ) - this is available only as specialized, by inherited classed like SVG, HTML?");
399 }
400 // DANGER, without cast?
401 // std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? " << type << '=' << std::endl;
402 // std::cerr << __FILE__ << ':' << __FUNCTION__ << " dict: " << drain::sprinter(drain::EnumDict<T>::dict) << std::endl;
403 }
404 */
405
406
408 //typedef std::map<std::string,std::string> xmldoc_attrib_map_t;
409 typedef std::list<std::pair<std::string,std::string> > xmldoc_attrib_map_t;
410 static xmldoc_attrib_map_t xmldoc_attribs;
411
412
413};
414
415template <class T>
416void NodeXML<T>::swap(NodeXML<T> & node){
417 // Swap attributes
419 // Swap classes
420 this->classList.swap(node.classList);
421}
422
423
424
425/*
426 Impossible. Cannot construct final object, for example members are not available for #link() .
427template <>
428inline
429void NodeXML<int>::handle Type(const int & type){
430 // DANGER, without cast?
431 std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? " << type << '=' << std::endl;
432 std::cerr << __FILE__ << ':' << __FUNCTION__ << " dict: " << drain::sprinter(drain::EnumDict<int,XML>::dict) << std::endl;
433}
434*/
435
436template <>
437inline
438const std::string & NodeXML<int>::getTag() const {
439 return drain::EnumDict<int,XML>::dict.getKey(this->type, false);
440}
441
442typedef NodeXML<>::xml_tree_t TreeXML;
443//typedef drain::UnorderedMultiTree<NodeXML<>,false, NodeXML<>::path_t> TreeXML;
444
445// NOTE: template will not match for subclasses of NodeXML<E> because default template will match any class exactly.
446template <class E, bool EX, class P>
447struct TypeName< drain::UnorderedMultiTree<NodeXML<E>,EX,P> > {
448
449 static const std::string & str(){
450 static const std::string name = drain::StringBuilder<>("TreeXML<", TypeName<E>::str(), ">");
451 return name;
452 }
453
454};
455
456
457
458
459template <class N>
460std::ostream & NodeXML<N>::nodeToStream(std::ostream &ostr, tag_display_mode mode) const {
461
462
463 if (isCText()){
464 if (mode != CLOSING_TAG){ // or: OPENING
465 ostr << ctext; // << '(' << mode << ')'; // << " /-->\n";
466 }
467 return ostr;
468 }
469 else if (isComment()){
470 // Remember: a large subtree can be commented out
471 if (mode != CLOSING_TAG){
472 ostr << "<!--"; // << ctext; // << " /-->\n";
473 }
474 }
475 else {
476
477 if (isUndefined()){
478 drain::Logger(__FILE__, __FUNCTION__).warn("Undefined TAG type for ", getName(), " ID=", getId(), " attr=", getAttributes());
479 }
480
481 if (mode==CLOSING_TAG){
482 ostr << "</";
483 }
484 else {
485 ostr << '<';
486 }
487
488 if (getTag().empty()){
489 drain::Logger(__FILE__, __FUNCTION__).unimplemented<LOG_ERR>("defaultTag for type=", getType(), " requested by ID=", getId(), " attr=", getAttributes());
490
491 ostr << "defaultTag"; // << ' '; FIX! getDefaultTag?
492 }
493 else {
494 ostr << getTag(); // << ' ';
495 // TODO check GDAL XML
496 // if (!defaultTag.empty())
497 // attribToStream(ostr, "name", defaultTag);
498 }
499 }
500
501 if (mode != CLOSING_TAG){
502
503 if (typeIs(STYLE)){
504 // xmlAttribToStream(ostr, "data-mode", "experimental");
505 }
506 else { // if (!isCText())
507
508 specificAttributesToStream(ostr);
509
510 char sep=0;
511
512 // Iterate attributes - note: also for comment
513 for (const auto & key: getAttributes().getKeyList()){
514 std::string v = get(key, "");
515 // Skip empties (so Sprinter::toStream not applicable)
516 if (!v.empty()){
517 xmlAttribToStream(ostr, key, v);
518 sep=' ';
519 }
520 }
521
522 // Handle CSS style separately
523 if (!style.empty()){
524 if (sep)
525 ostr << sep;
526 ostr << "style=\"";
527 Sprinter::sequenceToStream(ostr, style, StyleXML::styleLineLayout);
528 ostr << '"'; // << ' ';
529 }
530
531 /*
532 if (!ctext.empty()){
533 ostr << " "; // debugging
534 }
535 */
536 }
537
538 }
539
540 // END
541 if (isComment()){
542 ostr << ' '; // prefix for free ctext
543 if (mode != OPENING_TAG){
544 // it is EMPTY_TAG or CLOSING TAG
545 ostr << "/-->"; // \n
546 }
547 // warn if has children? or comment them??
548 }
549 else if (mode==EMPTY_TAG){ // OR no ctext!
550 // close TAG
551 ostr << "/>"; // \n <- check newline - add before indent?
552 }
553 else {
554 ostr << ">";
555 }
556
557 return ostr;
558
559}
560
561
562template <class N>
563inline
564std::ostream & operator<<(std::ostream &ostr, const NodeXML<N> & node){
565 return node.nodeToStream(ostr);
566}
567
569
576DRAIN_ENUM_DICT2(int,XML);
577
578//template <>
579//const drain::EnumDict<int,XML>::dict_t drain::EnumDict<int,XML>::dict;
580
581
582template <class E, bool EX, class P>
583std::ostream & operator<<(std::ostream &ostr, const UnorderedMultiTree<NodeXML<E>,EX,P> & tree){
584 // DOC def? TODO: preamble/prologToStream()
585 NodeXML<E>::docTypeToStream(ostr); // must be member, to support virtual?
586 NodeXML<E>::toStream(ostr, tree, "");
587 return ostr;
588}
589
590
591
592/*
593inline
594std::ostream & operator<<(std::ostream &ostr, const TreeXML & t){
595 // DOC def? TODO: preamble/prologToStream()
596 TreeXML::node_data_t::docTypeToStream(ostr); // must be member, to support virtual?
597 TreeXML::node_data_t::toStream(ostr, t, "");
598 return ostr;
599}
600*/
601
602
603
604
605} // drain::
606
607#endif /* TREEXML_H_ */
608
Definition Castable.h:76
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:313
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:431
Logger & unimplemented(const TT &... args)
Feature to be done. Special type of Logger::note().
Definition Log.h:512
Logger & deprecating(const TT &... args)
Feature will be removed. Special type of Logger::note().
Definition Log.h:522
A "handle" for specialized element classes, i.e. with members like width , height or radius .
Definition TreeXML.h:92
Definition TreeXML.h:341
static std::ostream & docTypeToStream(std::ostream &ostr)
Write the XML definition beginning any XML document.
Definition TreeXML.h:365
virtual const std::string & getTag() const
Definition TreeXML.h:276
std::list< std::pair< std::string, std::string > > xmldoc_attrib_map_t
Internal function called after setType()
Definition TreeXML.h:409
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:460
static const std::string & getTag(const T &type)
Definition TreeXML.h:285
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:376
NodeXML()
Default constructor.
Definition TreeXML.h:112
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:202
NodeXML(const NodeXML &node)
Copy constructor.
Definition TreeXML.h:126
Definition Path.h:112
A map of references to base type scalars, arrays or std::string; changing values in either are equiva...
Definition ReferenceMap.h:69
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:325
Definition StringBuilder.h:58
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:586
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 another tree structure to another.
Definition XML.h:651
Definition DataSelector.cpp:1277
A container for a static dictionary of enumeration values.
Definition EnumFlags.h:69
static const std::string & getKey(const std::string &s, bool lenient=true)
Convenience for object.set(...) like commands.
Definition EnumFlags.h:162
static const std::string name
Default implementation: name returned by std::type_info::name()
Definition Type.h:549