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 TREE_XML
41#define TREE_XML
42
43#include <ostream>
44
45#include <drain/Sprinter.h>
46#include <drain/FlexibleVariable.h>
47
48#include "ClassXML.h"
49#include "Flags.h"
50#include "ReferenceMap.h"
51#include "TreeUnordered.h"
52
53namespace drain {
54
55
60class StyleXML : public ReferenceMap2<FlexibleVariable> {
61
62public:
63
64 inline
65 StyleXML(){};
66
67 static const SprinterLayout styleLineLayout;
68 static const SprinterLayout styleRecordLayout;
69 static const SprinterLayout styleRecordLayoutActual;
70
71};
72
73
74inline
75std::ostream & operator<<(std::ostream &ostr, const StyleXML & style){
77 return ostr;
78}
79
80class XML : protected ReferenceMap2<FlexibleVariable> {
81public:
82
83
84 static const int UNDEFINED = 0;
85 static const int COMMENT = 1;
86 static const int CTEXT = 2;
87 static const int STYLE = 3;
88 static const int SCRIPT = 4;
89
91
93
94 // String, still easily allowing numbers through set("id", ...)
95 std::string id;
96
97 // Consider either/or
98 std::string ctext;
99
100 std::string url;
101
102 template <class V>
103 static inline
104 void attribToStream(std::ostream &ostr, const std::string & key, const V &value){
105 ostr << ' ' << key << '=' << '"' << value << '"'; // << ' ';
106 }
107
108 static int nextID;
109
111 typedef drain::Path<std::string,'/'> path_t; // consider xml_path_t
112 typedef path_t::elem_t path_elem_t;
113
114 inline
115 static int getCount(){
116 return nextID;
117 }
118
120
123 inline
124 void setId(){
125 link("id", id);
126 }
127
129 inline
130 void setId(const std::string & s){
131 link("id", id = s);
132 }
133
134 template <char C='\0', typename ...TT>
135 inline
136 void setId(const TT & ...args) {
137 link("id", id = drain::StringBuilder<C>(args...));
138 }
139
141 inline
142 const std::string & getId() const {
143 return id;
144 }
145
146 inline
147 bool empty() const {
148 return map_t::empty();
149 }
150
151 inline
152 const map_t & getAttributes() const {
153 return *this;
154 };
155
156 // Maybe controversial. Helps importing sets of variables.
157 inline
158 map_t & getAttributes(){
159 return *this;
160 };
161
162
164 // But otherways confusing?
165 virtual inline
166 void setAttribute(const std::string & key, const std::string &value){
167 (*this)[key] = value;
168 }
169
171 // But otherways confusing?
172 virtual inline
173 void setAttribute(const std::string & key, const char *value){
174 (*this)[key] = value; // -> handleString()
175 }
176
178 template <class V>
179 inline
180 void setAttribute(const std::string & key, const V & value){
181 (*this)[key] = value; // -> handleString()
182 }
183
184
185 inline
186 void remove(const std::string & s){
187 iterator it = this->find(s);
188 if (it != this->end()){
189 this->erase(it);
190 }
191 }
192
193
194 inline
195 const drain::FlexibleVariable & get(const std::string & key) const {
196 return (*this)[key];
197 }
198
199 inline
200 drain::FlexibleVariable & get(const std::string & key){
201 return (*this)[key];
202 }
203
204
205 template <class V>
206 inline
207 V get(const std::string & key, const V & defaultValue) const {
208 return map_t::get(key, defaultValue);
209 }
210
211 inline
212 std::string get(const std::string & key, const char * defaultValue) const {
213 return map_t::get(key, defaultValue);
214 }
215
217
218 template <typename ... TT>
219 inline
220 void addClass(const TT &... args) {
221 classList.add(args...);
222 }
223
224 /*
225 template <typename ... TT>
226 inline
227 void addClass(const std::string & s, const TT &... args) {
228 classList.insert(s);
229 addClass(args...);
230 }
231 */
232
236 template <class V>
237 inline
238 bool hasClass(const V & cls) const {
239 return classList.has(cls);
240 }
241
242 inline
243 void removeClass(const std::string & s) {
244 classList.remove(s);
245 }
246
247 inline
248 void clearClasses(){
249 classList.clear();
250 }
251
252 // ------------------ Style Class ---------------
253
254
255 ClassListXML classList;
256
257 typedef std::list<path_t> path_list_t;
258
259 StyleXML style;
260
262
273 // This could also be in TreeXMLutilities
274 template <class V>
275 static
276 bool findById(const V & tree, const std::string & tag, typename V::path_t & result, const typename V::path_t & path = path_t());
277
279
289 // This could also be in TreeXMLutilities
290 template <class V>
291 static
292 bool findById(const V & tree, const std::string & tag, path_list_t & result, const path_t & path = path_t());
293
296 template <class V, class T>
297 static
298 bool findByTag(const V & tree, const T & tag, path_list_t & result, const path_t & path = path_t());
299
301 // This could also be in TreeXMLutilities
306 template <class V, class T>
307 static
308 bool findByTags(const V & tree, const std::set<T> & tags, path_list_t & result, const path_t & path = path_t());
309
311
317 template <class T2, class C>
318 static
319 bool findByClass(const T2 & t, const C & cls, std::list<path_elem_t> & result);
320
322
327 //template <class V, class E>
328 template <class V, class C>
329 static inline
330 bool findByClass(const V & t, const C & cls, path_list_t & result, const path_t & path = path_t());
331
332
333
334};
335
336
340template <class T=int>
341class NodeXML : public XML {
342
343public:
344
345
347 typedef T elem_t; // consider xml_elem_t
348 elem_t type;
349
350 typedef NodeXML<T> xml_node_t;
351
352
353 typedef UnorderedMultiTree<NodeXML<T>,false, path_t> xml_tree_t;
354
355
356 inline
357 NodeXML(const elem_t & t = elem_t(0)){
358 type = t;
359 drain::StringTools::import(++nextID, id);
360 // id = getTag()+id; UNDEF
361 };
362
363 // Note: use default constructor in derived classes.
364 inline
365 NodeXML(const NodeXML & node){
366 //drain::StringTools::import(++nextID, id);
367 copyStruct(node, node, *this, RESERVE); // This may corrupt (yet unconstructed) object?
368 type = node.getType();
369 drain::StringTools::import(++nextID, id);
370 // id = getTag()+id; UNDEF
371 }
372
373
374 inline
375 ~NodeXML(){};
376
377
378 typedef std::map<T,std::string> tag_map_t;
379
380 static
381 tag_map_t tags;
382
383
384
385
386 virtual
387 void setType(const elem_t &t){
388 type = t;
389 // in derived classes, eg. drain::image::BaseGDAL
390 // warning: case value ‘...’ not in enumerated type
391 }
392
393 /* Consider this later, for user-defined (not enumerated) tag types.
394 virtual
395 void setType(const std::string & type);
396 */
397
398 inline
399 const elem_t & getType() const {
400 return type;
401 };
402
403 inline
404 bool typeIs(const elem_t &t) const {
405 return type == t;
406 };
407
408 /*
409 template <elem_t E>
410 inline
411 bool typeIs() const {
412 return type == E;
413 };*/
414
415
416 // Consider raising these to XML
417 inline
418 bool isComment() const {
419 return typeIs((elem_t)COMMENT);
420 }
421
422 inline
423 bool isCText() const {
424 return typeIs((elem_t)CTEXT);
425 }
426
427 inline
428 bool isUndefined() const {
429 return typeIs((elem_t)UNDEFINED);
430 //return ((int)getType() == UNDEFINED);
431 }
432
433// protected:
434
435 // virtual
436 bool isSelfClosing() const {
437
438 static
439 const std::set<elem_t> l = {(elem_t)SCRIPT};
440 return (l.find(this->getType()) == l.end()); // not in the set
441
442 //return false;
443 }
444
445 // template <int N>
446 static inline
447 const std::string & getTag(unsigned int index){
448 typename tag_map_t::const_iterator it = tags.find((elem_t)index);
449 if (it != tags.end()){
450 return it->second;
451 }
452 else {
453 // consider empty
454 static std::string dummy;
455 dummy = drain::StringBuilder<>("UNKNOWN-", index);
456 return dummy;
457 // throw std::runtime_error(drain::StringBuilder<':'>(__FILE__, __FUNCTION__, " tag [", static_cast<int>(index), "] missing from dictionary"));
458 }
459 };
460
461
462
463 inline
464 const std::string & getTag() const {
465 return getTag(type); // risky? converts enum to int .. and back.
466 };
467
468
469
470 // NEW: --------------
471
472 inline
473 void set(const NodeXML & node){
474 if (isUndefined()){
475 // Should make sense, and be safe. Esp. when exactly same node type, by templating
476 setType(node.getType());
477 }
478 else if (type == STYLE) {
479 drain::Logger mout(__FILE__, __FUNCTION__);
480 mout.suspicious("copying STYLE from node: ", node);
481 }
482 drain::SmartMapTools::setValues<map_t>(getAttributes(), node.getAttributes());
483 }
484
485 inline
486 void set(const elem_t & type){
487 setType(type);
488 }
489
490 inline
491 void set(const std::string & s){
492 if (type == STYLE){
493 SmartMapTools::setValues(style, StringTools::trim(s, "; \t\n"), ';', ':');
494 //drain::SmartMapTools::setValues<map_t,true>(getAttributes(), s);
495 }
496 else {
497 setText(s);
498 }
499 }
500
501 inline
502 void set(const char *s){
503 set(std::string(s));
504 }
505
506 inline
507 void set(const drain::Castable & s){
508 setText(s);
509 }
510
511 inline
512 void set(const std::initializer_list<Variable::init_pair_t > &l){
513 // TODO: redirect to set(key,value), for consistency
514 if (type == STYLE){
516 }
517 else {
518 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), l); // add new keys
519 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
520 }
521 }
522
523 template <class X>
524 inline
525 void set(const std::map<std::string, X> & args){
526 // TODO: redirect to set(key,value), for consistency
527 if (type == STYLE){
529 }
530 else {
531 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), args); // add new keys
532 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
533 }
534 }
535
536
537 template <class V>
538 inline
539 void set(const std::string & key, const V & value){
540 if (type == STYLE){
541 // Modify collection directly
542 setStyle(key, value);
543 }
544 else if (key == "style"){
545 // Modify collection
546 setStyle(value);
547 }
548 else if (key == "class"){
549 // mout.warn<LOG_DEBUG>("class");
550 std::string cls;
551 drain::StringTools::import(value, cls);
552 addClass(cls);
553 }
554 else {
555 setAttribute(key, value);
556 }
557
558 }
559
560
561
562 // Check char *
563 inline
564 NodeXML & operator=(const T & x){
565 set(x);
566 return *this;
567 }
568
569 inline
570 NodeXML & operator=(const Castable &c){
571 setText(c);
572 return *this;
573 }
574
575
576 inline
577 NodeXML & operator=(const std::string &s){
578 setText(s);
579 return *this;
580 }
581
582 inline
583 NodeXML & operator=(const char *s){
584 setText(s);
585 return *this;
586 }
587
588 inline
589 NodeXML & operator=(const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
590 set(l);
591 return *this;
592 }
593
595
599 inline
600 NodeXML & setComment(const std::string & text = "") {
601
602 setType((elem_t)COMMENT);
603
604 if ((int)getType() != COMMENT){ //cross-check
605 throw std::runtime_error(drain::TypeName<NodeXML<T> >::str() + ": COMMENT not supported");
606 }
607
608 ctext = text;
609 return *this;
610 }
611
613
616 template <class S>
617 inline
618 // NodeXML & setText(const std::string & text = "") {
619 NodeXML & setText(const S & value) {
620 if (isUndefined()){
621 setType((elem_t)CTEXT);
622 if (!isCText()){ //cross-check
623 throw std::runtime_error(drain::TypeName<NodeXML<T> >::str() + ": CTEXT not supported");
624 }
625 }
626 else if (typeIs((elem_t)STYLE)){
627 setStyle(value); //
628 // SmartMapTools::updateValues(this->style, value, ';', ':');
629 //
630 }
631 drain::StringTools::import(value, ctext);
632 return *this;
633 }
634
635 inline
636 NodeXML & setText(const char *value) {
637 setText(std::string(value));
638 return *this;
639 }
640
641 // ------------------ Style ---------------
642
643
644 template <class S>
645 inline
646 void setStyle(const S &value){
647 drain::Logger mout(__FILE__, __FUNCTION__);
648 mout.error("unsupported type ", drain::TypeName<S>::str(), " for value: ", value);
649 }
650
651 void setStyle(const std::string & value){
652 drain::Logger mout(__FILE__, __FUNCTION__);
653 if (isUndefined()){
654 mout.suspicious("setting style for undefined elem: ", *this);
655 }
656 else if (type == STYLE){
657 mout.warn("setting style for STYLE elem: ", *this);
658 }
659 SmartMapTools::setValues(style, StringTools::trim(value, "; \t\n"), ';', ':');
660 }
661
662 void setStyle(const char *value){
663 setStyle(std::string(value));
664 }
665
666 inline
667 void setStyle(const std::string & key, const std::string & value){
668 // const std::initializer_list<Variable::init_pair_t > &l
669 // drain::Logger mout(__FILE__, __FUNCTION__);
670 // mout.special<LOG_WARNING>("Spezial str");
671 this->style[key] = value;
672 }
673
674
676
682 template <class V>
683 inline
684 void setStyle(const std::string & key, const std::initializer_list<V> &l){
685 // const std::initializer_list<Variable::init_pair_t > &l
686 if (type == STYLE){ // typeIs(STYLE) fails
687 drain::Logger mout(__FILE__, __FUNCTION__);
688 mout.warn("Setting style of STYLE? initializer_list<", drain::TypeName<V>::str(), "> = ", sprinter(l)); // , StyleXML::styleLineLayout ?
689 //mout.revised<LOG_WARNING>("Element is not STYLE but ", getTag(), ", initializer_list<", drain::TypeName<V>::str(), "> = ", sprinter(l)); // , StyleXML::styleLineLayout ?
690 }
691 this->style[key] = l;
692 }
693
694
696
699 template <class V>
700 inline
701 void setStyle(const std::string & key, const V & value){
702 // drain::Logger mout(__FILE__, __FUNCTION__);
703 if (type == STYLE){
704 drain::Logger mout(__FILE__, __FUNCTION__);
705 // "reuse" style map as style record map
706 std::stringstream sstr;
707 drain::Sprinter::toStream(sstr, value, StyleXML::styleLineLayout);
708 mout.warn("Setting style of STYLE?, arg type=", drain::TypeName<V>::str());
709 mout.warn("Check results: skipped ", sstr.str());
710 mout.warn("Check results: applied ", value);
711 this->style[key] = value; //sstr.str();
712 }
713 else {
714 // mout.special<LOG_WARNING>("Spezial ", drain::TypeName<V>::str());
715 this->style[key] = value;
716 }
717 }
718
719
720 inline
721 void setStyle(const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
723 }
724
725
728
729
730
731 template <class V>
732 static inline
733 std::ostream & docToStream(std::ostream & ostr, const V & tree){
734 V::node_data_t::xml_node_t::docTypeToStream(ostr);
735 V::node_data_t::xml_node_t::toStream(ostr, tree);
736 return ostr;
737 }
738
740 template <class V>
741 static
742 std::ostream & toStream(std::ostream &ostr, const V & t, const std::string & defaultTag = "", int indent=0);
743
745
749 static // virtual
750 inline
751 std::ostream & docTypeToStream(std::ostream &ostr){
752 ostr << "<?xml ";
753 for (const auto & entry: xmldoc_attribs){
754 attribToStream(ostr, entry.first, entry.second);
755 }
756 ostr << "?>";
757 ostr << '\n';
758 return ostr;
759 }
760
761 // drain::NodeHTML::HTML
762 // typedef std::pair<key_t,xml_node_t> node_pair_t;
763 // TODO: where is this needed?
764 template <int E>
765 static inline
766 const std::pair<key_t,NodeXML<T> > & entry(){
767 static const elem_t elem = (elem_t)E;
768 static const std::pair<key_t,NodeXML<T> > nodeEntry(getTag(E), elem); // note: converts tag (string) to key_t if needed.
769 return nodeEntry;
770 }
771
772
773
774
775
776protected:
777
778 typedef std::map<std::string,std::string> xmldoc_attrib_map_t;
779
780 static xmldoc_attrib_map_t xmldoc_attribs;
781
782 //inline void addClass(){}
783
784
785 // TODO: consider TAG from dict?
786 // std::string tag;
787
788
789};
790
791/*
792
793template <class N>
794int NodeXML<N>::nextID = 0;
795
796template <class T>
797const int NodeXML<T>::UNDEFINED(0);
798
799template <class T>
800const int NodeXML<T>::COMMENT(1);
801
802template <class T>
803const int NodeXML<T>::CTEXT(2);
804
805template <class T>
806const int NodeXML<T>::STYLE(3);
807
808template <class T>
809const int NodeXML<T>::SCRIPT(4);
810*/
811
812typedef drain::UnorderedMultiTree<NodeXML<>,false, NodeXML<>::path_t> TreeXML;
813
814// NOTE: template will not match for subclasses of NodeXML<E> because default template will match any class exactly.
815template <class E, bool EX, class P>
816struct TypeName< drain::UnorderedMultiTree<NodeXML<E>,EX,P> > {
817
818 static const std::string & str(){
819 static const std::string name = drain::StringBuilder<>("TreeXML<", TypeName<E>::str(), ">");
820 return name;
821 }
822
823 static const char* get(){
824 return str().c_str();
825 }
826};
827
828
829// Experimental.
830template <>
831TreeXML & TreeXML::addChild(const TreeXML::key_t & key);
832
833
834
835//template <class N>
836template <class T>
837//bool NodeXML<N>::findById(const T & t, const std::string & id, typename T::path_t & result, const typename T::path_t & path){
838bool XML::findById(const T & t, const std::string & id, typename T::path_t & result, const typename T::path_t & path){
839
840 if (t->id == id){
841 result = path;
842 return true;
843 }
844
845 // Recursion
846 for (const auto & entry: t){
847 if (findById(entry.second, id, result, path_t(path, entry.first))){
848 return true;
849 }
850 }
851
852 return false;
853 //return !result.empty();
854}
855
856
857
858// template <class N> NodeXML<N>
859template <class T>
860bool XML::findById(const T & t, const std::string & id, NodeXML<>::path_list_t & result, const path_t & path){
861
862 if (t->id == id){
863 result.push_back(path);
864 }
865
866 for (const auto & entry: t){
867 findById(entry.second, id, result, path_t(path, entry.first));
868 }
869
870 return !result.empty();
871}
872
876//template <class N>
877template <class T, class N>
878bool XML::findByTag(const T & t, const N & tag, NodeXML<>::path_list_t & result, const path_t & path){
879
880 // const T & t = tree(path);
881
882 if (t->typeIs(tag)){
883 result.push_back(path);
884 }
885
886 for (const auto & entry: t){
887 findByTag(entry.second, tag, result, path_t(path, entry.first));
888 }
889
890 //return result;
891 return !result.empty();
892}
893
897//template <class N>
898template <class T,class N>
899bool XML::findByTags(const T & t, const std::set<N> & tags, NodeXML<>::path_list_t & result, const path_t & path){
900
901 // const T & t = tree(path);
902
903 //if (t->typeIs(tag)){
904 if (tags.count(t->getType()) > 0){
905 result.push_back(path);
906 }
907
908 for (const auto & entry: t){
909 findByTags(entry.second, tags, result, path_t(path, entry.first));
910 }
911
912 //return result;
913 return !result.empty();
914}
915
916
917//template <class N>
918// template <class T>
919//bool NodeXML<N>::findByClass(const T & t, const std::string & cls, NodeXML<>::path_list_t & result, const path_t & path){
920
921template <class T2, class C> // NodeXML<N>
922//bool XML::findByClass(const T2 & t, const C & cls, NodeXML<>::path_list_t & result, const path_t & path){
923bool XML::findByClass(const T2 & t, const C & cls, XML::path_list_t & result, const path_t & path){
924
925 // drain::Logger mout(__FILE__,__FUNCTION__);
926
927 if (t->classList.has(cls)){
928 result.push_back(path);
929 }
930
931 for (const auto & entry: t){
932 // mout.warn(t->get("name", "<name>"), "... continuing to: ", path_t(path, entry.first));
933 findByClass(entry.second, cls, result, path_t(path, entry.first));
934 }
935
936 return !result.empty();
937}
938
939// template <class N>
940template <class T2, class C> // NodeXML<N>
941bool XML::findByClass(const T2 & t, const C & cls, std::list<path_elem_t> & result){
942
943 for (const auto & entry: t){
944 if (entry.second->hasClass(cls)){
945 result.push_back(entry.first);
946 }
947 }
948
949 return !result.empty();
950}
951
952
953
955
958template <class N>
959inline
960std::ostream & operator<<(std::ostream &ostr, const NodeXML<N> & node){
961
962 //ostr << node.getTag() << '<' << (unsigned int)node.getType() << '>' << ' ';
963 ostr << '<' << node.getTag() << '>' << ' ';
964
965 // drain::Sprinter::toStream(ostr, node.getAttributes(), drain::Sprinter::jsonLayout);
966 // drain::Sprinter::toStream(ostr, node.getAttributes().getMap(), drain::Sprinter::jsonLayout);
967 //
968 if (!node.getAttributes().empty()){
970 ostr << ' ';
971 }
972 if (!node.classList.empty()){
973 //ostr << '['; // has already braces []
974 //drain::Sprinter::toStream(ostr, node.classList, drain::Sprinter::pythonLayout);
975 drain::Sprinter::toStream(ostr, node.classList, ClassListXML::layout);
976 //ostr << ']' << ' ';
977 ostr << ' ';
978 }
979 if (!node.style.empty()){
980 ostr << '{';
981 drain::Sprinter::toStream(ostr, node.style);
982 ostr << '}' << ' ';
983 }
984 if (!node.ctext.empty()){
985 ostr << "'";
986 if (node.ctext.length() > 20){
987 ostr << node.ctext.substr(0, 15);
988 }
989 else {
990 ostr << node.ctext;
991 }
992 ostr << "'";
993 }
994 return ostr;
995}
996
998
1004template <class N>
1005template <class T>
1006std::ostream & NodeXML<N>::toStream(std::ostream & ostr, const T & tree, const std::string & defaultTag, int indent){
1007
1008
1009 const typename T::container_t & children = tree.getChildren();
1010
1011 // Indent
1012 //std::fill_n(std::ostream_iterator<char>(ostr), 2*indent, ' ');
1013 std::string fill(2*indent, ' ');
1014 ostr << fill;
1015
1016 // Start dag
1017 if (tree->isComment()){
1018 ostr << "<!-- " << tree->getTag() << ' ' << tree->ctext; // << " /-->\n";
1019 }
1020 else if (tree->isCText()){
1021 ostr << tree->ctext; // << " /-->\n";
1022 }
1023 else if (tree->getTag().empty())
1024 ostr << '<' << defaultTag; // << ' ';
1025 else {
1026 ostr << '<' << tree->getTag(); // << ' ';
1027 // TODO check GDAL XML
1028 //if (!defaultTag.empty())
1029 // attribToStream(ostr, "name", defaultTag);
1030 }
1031
1032 if (tree->typeIs((elem_t)STYLE)){
1033 //ostr << ' ';
1034 attribToStream(ostr, "data-mode", "experimental");
1035 // Sprinter::sequenceToStream(ostr, tree->style, StyleXML::styleRecordLayout);
1036 // ostr << "\n /-->";
1037 }
1038 else if (!tree->isCText()){
1039 //char sep=' ';
1040 if (!tree->classList.empty()){
1041 ostr << " class=\"";
1042 drain::Sprinter::toStream(ostr, tree->classList, ClassListXML::layout);
1043 // std::copy(tree->classList.begin(), tree->classList.end(), std::ostream_iterator<std::string>(ostr, " "));
1044 ostr << '"'; //ostr << "\"";
1045 }
1046
1047 // Iterate attributes - note: also for comment
1048 // Checking empties, so Sprinter::toStream not applicable
1049 for (const typename T::node_data_t::key_t & key: tree.data.getKeyList()){
1050 if (!tree.data[key].empty()){
1051 std::stringstream sstr;
1052 sstr << tree.data[key]; // consider checking 0, not only empty string "".
1053 if (!sstr.str().empty()){
1054 attribToStream(ostr, key, sstr.str());
1055 }
1056 }
1057 //ostr << ' ';
1058 }
1059
1060 // TAG style
1061 if (!tree->style.empty()){
1062 ostr << " style=\"";
1063 Sprinter::sequenceToStream(ostr, tree->style, StyleXML::styleLineLayout);
1064 //Sprinter::mapToStream(ostr, tree->style, StyleXML::styleLineLayout);
1065 ostr << '"'; // << ' ';
1066 }
1067
1068
1069 }
1070 else {
1071 if (!tree.data.empty()){
1072 // ??
1073 }
1074 }
1075
1076 // END TAG
1077 if (tree->isComment()){
1078 ostr << " /-->\n";
1079 }
1080 else if (tree->isCText()){
1081 ostr << '\n';
1082 }
1083 else if (tree.data.isSelfClosing() &&
1084 (!tree->typeIs((elem_t)STYLE)) && (!tree->typeIs((elem_t)SCRIPT)) &&
1085 (children.empty()) && tree->ctext.empty() ){ // OR no ctext!
1086 // close TAG
1087 ostr << "/>\n";
1088 //ostr << '/' << '>';
1089 //ostr << '\n';
1090 }
1091 else {
1092 // close starting TAG ...
1093 ostr << '>';
1094
1095 // ... and write contents
1096
1097 /*
1098 if (!tree->style.empty()){
1099 ostr << "<!-- STYLE? ";
1100 drain::Sprinter::toStream(ostr, tree->style.getMap(), drain::Sprinter::xmlAttributeLayout);
1101 ostr << "/-->\n";
1102 }
1103 */
1104
1105 if (tree->typeIs((elem_t)STYLE)){
1106 // https://www.w3.org/TR/xml/#sec-cdata-sect
1107 // ostr << "<![CDATA[ \n";
1108 if (!tree->ctext.empty()){
1109 // TODO: indent
1110 ostr << fill << tree->ctext << " /* CTEXT? */" << '\n';
1111 }
1112 if (!tree->getAttributes().empty()){
1113 ostr << "\n\t /* <!-- DISCARDED attribs ";
1114 drain::Logger mout(__FILE__,__FUNCTION__);
1115 mout.warn("STYLE elem contains attributes, probably meant as style: ", tree.data);
1116 Sprinter::toStream(ostr, tree->getAttributes()); //, StyleXML::styleRecordLayout
1117 ostr << " /--> */" << '\n';
1118 }
1119 if (!tree->style.empty()){
1120 ostr << fill << "/** style obj **/" << '\n';
1121 for (const auto & attr: tree->style){
1122 ostr << fill << " ";
1123 Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
1124 //attr.first << ':' attr.first << ':';
1125 ostr << '\n';
1126 }
1127 // ostr << fill << "}\n";
1128 // Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
1129 // ostr << '\n';
1130 }
1131 ostr << '\n';
1132 // ostr << fill << "<!-- elems /-->" << '\n';
1133 ostr << fill << "/* elems */" << '\n';
1134 for (const auto & entry: tree.getChildren()){
1135 if (!entry.second->ctext.empty()){
1136 //ostr << fill << "<!-- elem("<< entry.first << ") ctext /-->" << '\n';
1137 ostr << fill << " " << entry.first << " {" << entry.second->ctext << "} /* CTEXT */ \n";
1138 }
1139 if (!entry.second->getAttributes().empty()){
1140 //ostr << fill << "<!-- elem("<< entry.first << ") attribs /-->" << '\n';
1141 ostr << fill << " " << entry.first << " {\n";
1142 for (const auto & attr: entry.second->getAttributes()){
1143 ostr << fill << " ";
1144 ostr << attr.first << ':' << attr.second << ';';
1145 //Sprinter::pairToStream(ostr, attr, StyleXML::styleLineLayout); // {" :;"}
1146 // Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
1147 // attr.first << ':' attr.first << ':';
1148 ostr << '\n';
1149 }
1150 ostr << fill << " }\n";
1151 //Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
1152 ostr << '\n';
1153 }
1154 // Sprinter::sequenceToStream(ostr, entry.second->style, StyleXML::styleRecordLayout);
1155 }
1156 ostr << "\n"; // end CTEXT
1157 //ostr << " ]]>\n"; // end CTEXT
1158 // end STYLE defs
1159 }
1160 else {
1161
1162 if (tree->ctext.empty())
1163 ostr << '\n'; // TODO nextline
1164 else
1165 ostr << tree->ctext;
1166
1168 for (const auto & entry: children){
1169 toStream(ostr, entry.second, entry.first, indent+1); // no ++
1170 //ostr << *it;
1171 }
1172 // add end </TAG>
1173
1174 }
1175
1176 if (tree->typeIs((elem_t)STYLE) || !children.empty()){
1177 ostr << fill;
1178 //std::fill_n(std::ostream_iterator<char>(ostr), 2*indent, ' ');
1179 }
1180
1181 ostr << '<' << '/' << tree->getTag() << '>';
1182 ostr << '\n'; // TODO nextline
1183
1184 //if (tree.data.id >= 0)
1185 // ostr << "<!-- " << tree.data.id << " /-->\n";
1186 }
1187 return ostr;
1188}
1189
1190
1191
1192
1193inline
1194std::ostream & operator<<(std::ostream &ostr, const TreeXML & t){
1195 // DOC def? TODO: preamble/prologToStream()
1196 TreeXML::node_data_t::docTypeToStream(ostr); // must be member, to support virtual?
1197 TreeXML::node_data_t::toStream(ostr, t, "");
1198 return ostr;
1199}
1200
1201
1202} // drain::
1203
1204#endif /* TREEXML_H_ */
1205
Definition Castable.h:76
void add(const std::string &arg, const TT &... args)
Add one or several classes.
Definition ClassXML.h:72
static const SprinterLayout layout
Uses spaces as separators.
Definition ClassXML.h:145
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:312
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:430
Definition TreeXML.h:341
static std::ostream & docTypeToStream(std::ostream &ostr)
Write the XML definition beginning any XML document.
Definition TreeXML.h:751
void setStyle(const std::string &key, const std::initializer_list< V > &l)
Set style of an element.
Definition TreeXML.h:684
T elem_t
Tag type, CTEXT or COMMENT.
Definition TreeXML.h:347
NodeXML & setComment(const std::string &text="")
Make this node a comment. Contained tree will not be delete. In current version, attributes will be r...
Definition TreeXML.h:600
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
static std::ostream & toStream(std::ostream &ostr, const V &t, const std::string &defaultTag="", int indent=0)
"Forward definition" of Tree::toOstream
void setStyle(const std::string &key, const V &value)
For element/class/id, assign ...
Definition TreeXML.h:701
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
ref_t & link(const std::string &key, F &x)
Associates a map entry with a variable.
Definition ReferenceMap.h:84
void copyStruct(const ReferenceMap2< FlexibleVariable > &m, const T2 &src, T2 &dst, extLinkPolicy policy=RESERVE)
Experimental. Copies references and values of a structure to another.
Definition ReferenceMap.h:145
@ RESERVE
Definition ReferenceMap.h:131
static void setValues(M &dst, const std::map< std::string, S > &srcMap)
Definition SmartMapTools.h:176
map_t::iterator iterator
Needed?
Definition SmartMap.h:80
const map_t & getMap() const
Definition SmartMap.h:206
std::string get(const std::string &key, const std::string &defaultValue) const
Retrieves a value, or default value if value is unset.
Definition SmartMap.h:127
static std::ostream & toStream(std::ostream &ostr, const std::initializer_list< T > &x, const SprinterLayout &layout=defaultLayout)
New (experimental)
Definition Sprinter.h:420
static const SprinterLayout xmlAttributeLayout
Like attributes in XML (HTML, SVG, ...) tags.
Definition Sprinter.h:227
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
static std::string trim(const std::string &s, const std::string &trimChars=" \t\n\r")
Returns a string without leading and trailing whitespace (or str undesired chars).
Definition String.cpp:170
Definition TreeXML.h:60
VariableT is a final class applied through typedefs Variable, Reference and FlexibleVariable.
Definition VariableT.h:87
Base class for XML "nodes", to be data elements T for drain::Tree<T>
Definition TreeXML.h:80
static bool findByClass(const T2 &t, const C &cls, std::list< path_elem_t > &result)
Finds child elements in an XML structure by class name.
Definition TreeXML.h:941
void addClass(const TT &... args)
Style class.
Definition TreeXML.h:220
void setId()
Makes ID a visible attribute.
Definition TreeXML.h:124
const std::string & getId() const
Returns ID of this element. Hopefully a unique ID...
Definition TreeXML.h:142
virtual void setAttribute(const std::string &key, const char *value)
Default implementation. Needed for handling units in strings, like "50%" or "640px".
Definition TreeXML.h:173
static bool findByClass(const V &t, const C &cls, path_list_t &result, const path_t &path=path_t())
Finds elements recursively in an XML structure by class name supplied as an enumeration type.
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 bool findById(const V &tree, const std::string &tag, path_list_t &result, const path_t &path=path_t())
Find the occurrence(s) of given ID using recursive breath-first search.
static bool findByTag(const V &tree, const T &tag, path_list_t &result, const path_t &path=path_t())
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.
Definition TreeXML.h:111
void setAttribute(const std::string &key, const V &value)
"Final" implementation.
Definition TreeXML.h:180
static bool findByTags(const V &tree, const std::set< T > &tags, path_list_t &result, const path_t &path=path_t())
"Forward definition"
bool hasClass(const V &cls) const
Definition TreeXML.h:238
std::string id
Some general-purpose.
Definition TreeXML.h:95
void setId(const std::string &s)
Makes ID a visible attribute, with a given value.
Definition TreeXML.h:130
Definition DataSelector.cpp:1277
Definition Sprinter.h:137
Definition Type.h:542
static const std::string name
Default implementation: name returned by std::type_info::name()
Definition Type.h:558