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::SmartMapTools::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/* This could be it, unless already defined...
457template <class N, bool EX, class P>
458inline
459drain::UnorderedMultiTree<N,EX,P> & drain::UnorderedMultiTree<N,EX,P>::addChild(const drain::UnorderedMultiTree<N,EX,P>::key_t & key){
460 return XML::xmlAddChild(*this, key);
461}
462*/
463
464/* doesnt work
465template <class E, bool EX, class P>
466inline
467drain::UnorderedMultiTree<NodeXML<E>,EX,P> & drain::UnorderedMultiTree<NodeXML<E>,EX,P>::addChild(const std::string & key){
468 return XML::xmlAddChild(*this, key);
469}
470*/
471
472/*
473template <class N, bool EX, class P>
474template <typename K> // for K (path elem arg)
475const typename drain::UnorderedMultiTree<N,EX,P>::key_t & drain::UnorderedMultiTree<N,EX,P>::getKey(const K & key){
476 return drain::EnumDict<K>::dict.getKey(key, false);
477}
478*/
479
480
481
482template <class N>
483std::ostream & NodeXML<N>::nodeToStream(std::ostream &ostr, tag_display_mode mode) const {
484
485
486 if (isCText()){
487 if (mode != CLOSING_TAG){ // or: OPENING
488 ostr << ctext; // << '(' << mode << ')'; // << " /-->\n";
489 }
490 return ostr;
491 }
492 else if (isComment()){
493 // Remember: a large subtree can be commented out
494 if (mode != CLOSING_TAG){
495 ostr << "<!--"; // << ctext; // << " /-->\n";
496 }
497 }
498 else {
499
500 if (mode==CLOSING_TAG){
501 ostr << "</";
502 }
503 else {
504 ostr << '<';
505 }
506
507 if (getTag().empty()){
508 drain::Logger(__FILE__, __FUNCTION__).unimplemented<LOG_ERR>("defaultTag for type=", getType(), " requested by for ID=", getId(), " attr=", getAttributes());
509
510 ostr << "defaultTag"; // << ' '; FIX! getDefaultTag?
511 }
512 else {
513 ostr << getTag(); // << ' ';
514 // TODO check GDAL XML
515 // if (!defaultTag.empty())
516 // attribToStream(ostr, "name", defaultTag);
517 }
518 }
519
520 if (mode != CLOSING_TAG){
521
522 if (typeIs(STYLE)){
523 // xmlAttribToStream(ostr, "data-mode", "experimental");
524 }
525 else { // if (!isCText())
526
527 specificAttributesToStream(ostr);
528
529 char sep=0;
530
531 // Iterate attributes - note: also for comment
532 for (const auto & key: getAttributes().getKeyList()){
533 std::string v = get(key, "");
534 // Skip empties (so Sprinter::toStream not applicable)
535 if (!v.empty()){
536 xmlAttribToStream(ostr, key, v);
537 sep=' ';
538 }
539 }
540
541 // Handle CSS style separately
542 if (!style.empty()){
543 if (sep)
544 ostr << sep;
545 ostr << "style=\"";
546 Sprinter::sequenceToStream(ostr, style, StyleXML::styleLineLayout);
547 ostr << '"'; // << ' ';
548 }
549
550 /*
551 if (!ctext.empty()){
552 ostr << " "; // debugging
553 }
554 */
555 }
556
557 }
558
559 // END
560 if (isComment()){
561 ostr << ' '; // prefix for free ctext
562 if (mode != OPENING_TAG){
563 // it is EMPTY_TAG or CLOSING TAG
564 ostr << "/-->"; // \n
565 }
566 // warn if has children? or comment them??
567 }
568 else if (mode==EMPTY_TAG){ // OR no ctext!
569 // close TAG
570 ostr << "/>"; // \n <- check newline - add before indent?
571 }
572 else {
573 ostr << ">";
574 }
575
576 return ostr;
577
578}
579
580
581template <class N>
582inline
583std::ostream & operator<<(std::ostream &ostr, const NodeXML<N> & node){
584 return node.nodeToStream(ostr);
585}
586
588
595template <>
597
598
599template <class E, bool EX, class P>
600std::ostream & operator<<(std::ostream &ostr, const UnorderedMultiTree<NodeXML<E>,EX,P> & tree){
601 // DOC def? TODO: preamble/prologToStream()
602 NodeXML<E>::docTypeToStream(ostr); // must be member, to support virtual?
603 NodeXML<E>::toStream(ostr, tree, "");
604 return ostr;
605}
606
607
608
609/*
610inline
611std::ostream & operator<<(std::ostream &ostr, const TreeXML & t){
612 // DOC def? TODO: preamble/prologToStream()
613 TreeXML::node_data_t::docTypeToStream(ostr); // must be member, to support virtual?
614 TreeXML::node_data_t::toStream(ostr, t, "");
615 return ostr;
616}
617*/
618
619
620
621
622} // drain::
623
624#endif /* TREEXML_H_ */
625
Definition Castable.h:76
Two-way mapping between strings and objects of template class T.
Definition Dictionary.h:63
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: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:483
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:321
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:585
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:661
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