Loading...
Searching...
No Matches
XML.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_XML
41#define DRAIN_XML
42
43#include <ostream>
44
45#include <drain/FlexibleVariable.h>
46#include <drain/MapTools.h> // NEW
47#include <drain/Sprinter.h>
48#include <drain/StringTools.h>
49
50#include "ClassXML.h"
51// #include "UtilsXML.h"
52// #include "Flags.h"
53#include "ReferenceMap.h"
54#include "StyleXML.h"
55
56namespace drain {
57
58
59
60
62//class XML : protected ReferenceMap2<FlexibleVariable> {
63//class XML : protected ReferenceMap2<FlexibleVariable> {
64class XML : protected std::map<std::string,FlexibleVariable> {
65
66public:
67
68 typedef std::map<std::string,FlexibleVariable> map_t;
69 //typedef ReferenceMap2<FlexibleVariable> map_t;
70
71 map_t & getMap(){
72 return *this;
73 }
74
75 const map_t & getMap() const {
76 return *this;
77 }
78
79 typedef int intval_t;
80
81 // TODO:
82 // static const intval_t flag_OPEN = 128;
83 // static const intval_t flag_TEXT = 256;
84 static const intval_t UNDEFINED = 0;
85 static const intval_t COMMENT = 1; // || flag_TEXT
86 static const intval_t CTEXT = 2; // || flag_TEXT
87 static const intval_t SCRIPT = 3; // || flag_EXPLICIT || flag_TEXT
88 static const intval_t STYLE = 4; // || flag_EXPLICIT
89 static const intval_t STYLE_SELECT = 5;
90 static const intval_t JAVASCRIPT = 6; // future extension
91 static const intval_t JAVASCRIPT_SCOPE = 7; // future extension
92
93
94 enum entity_t {
95 AMPERSAND = '&',
96 LESS_THAN = '<',
97 EQUAL_TO = '=',
98 GREATER_THAN = '>',
99 NONBREAKABLE_SPACE = ' ',
100 QUOTE = '"',
101 CURLY_LEFT = '{',
102 CURLY_RIGHT = '}',
103 // ---
104 TAB = '\t',
105 NEWLINE = '\n',
106 // ---
107 DEGREE = 176,
108 };
109
110 /* Variants of entity map */
111
113 static
114 const std::map<char,std::string> & getKeyConversionMap();
115
117 static
118 const std::map<char,std::string> & getAttributeConversionMap();
119
121 static
122 const std::map<char,std::string> & getCTextConversionMap();
124
125
126 inline
127 XML(){};
128
129 inline
130 XML(const XML &){
131 };
132
133 virtual inline
134 ~XML(){};
135
136 template <class T> // "final"
137 void setType(const T &t){ // DANGER, without cast?
138 const intval_t t2 = static_cast<intval_t>(t);
139 if (type != t2){
140 reset();
141 type = t2; // also UNDEFINED ok here
142 handleType(); // NOTE: problems, if copy constructor etc. calls setType on a base class – trying to link future members
143 }
144 // handleType(static_cast<T>(t)); REMOVED 2025/09
145 // in derived classes, eg. drain::image::BaseGDAL
146 // warning: case value ‘...’ not in enumerated type
147 }
148
149 // Consider this later, for user-defined (not enumerated) tag types.
150 // virtual
151 // void setType(const std::string & type);
152
153
154 inline
155 const intval_t & getType() const {
156 return type;
157 };
158
160 inline
161 bool typeIsSet() const {
162 return type != UNDEFINED;
163 };
164
166
169 template <class T2, class ...T3>
170 inline
171 bool typeIs(const T2 & arg, const T3... args) const {
172 if (type == static_cast<intval_t>(arg)){
173 return true;
174 }
175 else {
176 return typeIs(args...);
177 }
178 };
179
180
181 std::string ctext;
182
183 // Could be templated, behind Static?
184 static int nextID;
185
186 inline
187 static int getCount(){
188 return nextID;
189 }
190
191
192 inline
193 bool isUndefined() const {
194 return type == UNDEFINED;
195 }
196
197 inline
198 bool isComment() const {
199 return type == COMMENT;
200 }
201
202 inline
203 bool isCText() const {
204 return type == CTEXT;
205 }
206
207 inline
208 bool isStyle() const {
209 return type == STYLE;
210 }
211
212 /* HTML Only
213 inline
214 bool isLink() const {
215 return type == LINK;
216 }
217 */
218
219 inline
220 bool isScript() const {
221 return type == SCRIPT;
222 }
223
224 inline
225 bool isScopeJS() const {
226 return type == JAVASCRIPT_SCOPE;
227 }
228
230 virtual
231 bool isSingular() const;
232
234 virtual
235 bool isExplicit() const;
236
238
246 void reset();
257
260 inline
261 void setId(){
262 getMap()["id"].link(id);
263 //link("id", id);
264 }
265
267 inline
268 void setId(const std::string & s){
269 getMap()["id"].link(id=s);
270 // link("id", id = s);
271 }
272
274 template <char C='\0', typename ...TT>
275 inline
276 void setId(const TT & ...args) {
277 getMap()["id"].link(id=drain::StringBuilder<C>(args...));
278 // link("id", id = drain::StringBuilder<C>(args...));
279 }
280
282 inline
283 const std::string & getId() const {
284 return id;
285 }
286
287
289
293 template <class ...T>
294 inline
295 void setComment(const T & ...args) {
296 this->clear(); // what if also uncommenting needed?
297 // this->clearClasses();
298 type = COMMENT;
299 setText(args...);
300 }
301
303
308 virtual // redef shows variadic args, below?
309 void setText(const std::string & s);
310
311 template <class ...T>
312 void setText(const T & ...args) {
313 setText(StringBuilder<>(args...).str()); // str() to avoid infinite loop
314 }
315
316 template <class ...T>
317 void setTextSafe(const T & ...args) {
318 std::string dst;
319 StringTools::replace(StringBuilder<>(args...).str(), getCTextConversionMap(), dst); // str() to avoid infinite loop
320 setText(dst);
321 //setText(StringTools::replace(m, StringBuilder<>(args...).str(), ctext)); // str() to avoid infinite loop
322 }
323
324 virtual inline
325 const std::string & getText() const {
326 return ctext;
327 }
328
329 inline
330 const std::string & getUrl(){
331 return url;
332 }
333
337 virtual inline
338 void setUrl(const std::string & s){
339 url = s;
340 if (isScript()){
341 getMap()["url"].link(url);
342 // link("url", url);
343 }
344 }
345
346 template <class ...T>
347 inline
348 void setName(const T & ...args){
349 setAttribute("data-name", drain::StringBuilder<>(args...).str());
350 }
351
352 inline
353 const FlexibleVariable & getName() const {
354 return MapTools::get(getMap(), std::string("data-name"));
355 // return (*this)["data-name"];
356 }
357
358
359 // ---------------- Attributes ---------------
360
361 virtual inline // shadows - consider virtual
362 bool empty() const {
363 return map_t::empty();
364 }
365
366 inline
367 bool hasAttribute(const std::string & key){
368 return MapTools::hasKey(getMap(), key);
369 };
370
371 inline
372 const map_t & getAttributes() const {
373 return *this;
374 };
375
376 // Maybe controversial. Helps importing sets of variables.
377 inline
378 map_t & getAttributes(){
379 return *this;
380 };
381
382 // Rename getAttribute?
383 inline
384 const drain::FlexibleVariable & get(const std::string & key) const {
385 return MapTools::get(getMap(), key);
386 //return (*this)[key];
387 }
388
389 // Rename getAttribute?
390 inline
391 drain::FlexibleVariable & get(const std::string & key){
392 return MapTools::get(getMap(), key);
393 // return (*this)[key];
394 }
395
396
397 // Rename getAttribute?
398 template <class V>
399 inline
400 V get(const std::string & key, const V & defaultValue) const {
401 return MapTools::get(getMap(), key, defaultValue);
402 //return map_t::get(key, defaultValue);
403 }
404
405 // Rename getAttribute?
406 inline
407 std::string get(const std::string & key, const char * defaultValue) const {
408 return MapTools::get(getMap(), key, defaultValue);
409 //return map_t::get(key, defaultValue);
410 }
411
413 // But otherways confusing?
414 virtual inline
415 void setAttribute(const std::string & key, const std::string &value){
416 (*this)[key] = value;
417 }
418
420 // But otherways confusing?
421 virtual inline
422 void setAttribute(const std::string & key, const char *value){
423 (*this)[key] = value; // -> handleString()
424 }
425
426 /*
427 template <class V>
428 inline
429 void setAttribute(const std::string & key, const V & value){
430 (*this)[key] = value; // -> handleString()
431 }
432 */
433
435 template <class ... TT>
436 inline
437 void setAttribute(const std::string & key, const TT &... args){
438 (*this)[key] = StringBuilder<>(args...).str();
439 }
440
441
442
443 inline
444 void removeAttribute(const std::string & s){
445 iterator it = this->find(s);
446 if (it != this->end()){
447 this->erase(it);
448 }
449 }
450
451
452
453protected:
454
455 inline
456 bool typeIs() const {
457 return false;
458 };
459
460 intval_t type = XML::UNDEFINED;
461
462 // String, still easily allowing numbers through set("id", ...)
463 std::string id;
464 // Consider either/or
465 std::string url;
466
467 virtual inline
468 void handleType(){}; // = 0;
469
470
471public:
472
473 // ------------------ Style ---------------
474
475protected:
476
477 StyleXML style;
478
479public:
480
481 inline
482 const StyleXML & getStyle() const {
483 return style;
484 }
485
486 inline
487 void setStyle(const StyleXML & s){
488 style.clear();
489 MapTools::setValues(style, s);
490 }
491
492 void setStyle(const std::string & value){
493 drain::Logger mout(__FILE__, __FUNCTION__);
494 if (type == UNDEFINED){
495 mout.reject<LOG_WARNING>("setting style for UNDEFINED elem: ", value);
496 mout.unimplemented<LOG_WARNING>("future option: set type to STYLE_SELECT");
497 }
498 else if (type == STYLE){
499 mout.reject<LOG_WARNING>("not setting style for STYLE elem: ", value); // , *this);
500 }
501 else {
502 MapTools::setValues(style, value, ';', ':', "; \t\n"); // sep, equal, trim (also ';' ?)
503 }
504 }
505
506 inline
507 void setStyle(const char *value){
508 setStyle(std::string(value));
509 }
510
511 inline
512 void setStyle(const std::string & key, const std::string & value){
513 drain::Logger mout(__FILE__, __FUNCTION__);
514 if (type == UNDEFINED){
515 mout.reject<LOG_WARNING>("setting style for UNDEFINED elem: ", key, '=', value);
516 mout.unimplemented<LOG_WARNING>("future option: set type to STYLE_SELECT");
517 }
518 else if (type == STYLE){
519 mout.reject<LOG_WARNING>("not setting style for STYLE elem: ", value); // , *this);
520 }
521 else {
522 this->style[key] = value;
523 }
524 }
525
526
528
534 template <class V>
535 inline
536 void setStyle(const std::string & key, const std::initializer_list<V> &l){
537 // const std::initializer_list<Variable::init_pair_t > &l
538 if (type == STYLE){ // typeIs(STYLE) fails
539 drain::Logger mout(__FILE__, __FUNCTION__);
540 mout.warn("Setting style of STYLE? initializer_list<", drain::TypeName<V>::str(), "> = ", sprinter(l)); // , StyleXML::styleLineLayout ?
541 }
542 this->style[key] = l;
543 }
544
545
547
557
565 template <class ... TT>
566 inline
567 void setStyle(const std::string & key, const TT &... args){
568
569 if (type == STYLE){
570 drain::Logger(__FILE__, __FUNCTION__).reject<LOG_WARNING>("Setting style of STYLE: ", key, "=", args...);
571 }
572 else {
573 // In a variable map
574 this->style[key] = StringBuilder<>(args...).str();
575 }
576 }
577
578 inline
579 void setStyle(const std::initializer_list<std::pair<const char *,const drain::Variable> > &args){
580 //drain::SmartMapTools::setValues(style, args);
581 drain::MapTools::setValues(style, args);
582 }
583
584 template <class V>
585 void setStyle(const std::map<std::string, V> & args){
586 drain::MapTools::setValues(style, args);
587 }
588
589
590
591protected:
592
593 // ------------------ Style Class ---------------
594
595 ClassListXML classList;
596
597public:
598
599 const ClassListXML & getClasses() const {
600 return classList;
601 }
602
603 template <typename ... TT>
604 inline
605 void addClass(const TT &... args) {
606 classList.add(args...);
607 }
608
612 template <class V>
613 inline
614 bool hasClass(const V & cls) const {
615 return classList.has(cls);
616 }
617
618 inline
619 void removeClass(const std::string & s) {
620 classList.remove(s);
621 }
622
623 inline
624 void clearClasses(){
625 classList.clear();
626 }
627
628
629 virtual
630 void specificAttributesToStream(std::ostream & ostr) const;
631
632
633 enum tag_display_mode {
634 FLEXIBLE_TAG = 0, // <TAG>...</TAG> or <TAG/>
635 OPENING_TAG= 1, // <TAG>
636 CLOSING_TAG = 2, // </TAG>
637 EMPTY_TAG = OPENING_TAG | CLOSING_TAG, // element has no descendants: <hr/>
638 NON_EMPTY_TAG, // opening and closing tags must appear, even when empty: <script></script>
639 };
640
641
642 virtual
643 std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const = 0;
644
645
646 /*
647 template <class TR>
648 static
649 std::ostream & toStream(std::ostream & ostr, const TR & tree, const std::string & defaultTag="ELEM", int indent=0);
650 */
651
652 // , const std::string & defaultTag="ELEM" UnorderedMultiTree<N>
653 template <class N>
654 static
655 std::ostream & toStream(std::ostream & ostr, const UnorderedMultiTree<N> & tree, int indent=0);
656
657
658
660
662 static
663 const std::map<char,std::string> & getEntityMap();
664
666
670 // core utility (not to be external)
671 template <class V>
672 static inline
673 void xmlAttribToStream(std::ostream &ostr, const std::string & key, const V &value){
674 //StringTools::replace(XML::encodingMap, data.ctext, ostr);
675 //ostr << ' ' << key << '=' << '"' << value << '"'; // << ' ';
676
677 static const std::map<char,char> keyMap = {
678 {' ','_'},
679 {'"','_'},
680 {'=','_'},
681 };
682 ostr << ' ';
683 StringTools::replace(key, keyMap, ostr); // XML::encodingMap
684 //StringTools::replace(getEntityMap(), key, ostr); // XML::encodingMap
685
686 static const std::map<char,std::string> valueMap = {
687 {entity_t::QUOTE, "'"},
688 {entity_t::LESS_THAN,"(("},
689 {entity_t::GREATER_THAN,"))"},
690 };
691 ostr << '=' << '"';
692 StringTools::replace(value, valueMap, ostr); // XML::encodingMap
693 //StringTools::replace(getEntityMap(), value, ostr); // XML::encodingMap
694 ostr << '"';
695 //<< key << '=' << '"' << value << '"'; // << ' ';
696 }
697
698
700
705 template <typename N>
706 static inline
707 N & xmlAssignNode(N & dst, const N & src){
708
709 if (&src != &dst){
710 //dst.clear(); // clear attributes,
711 //if (!dst.typeIs(src.getNativeType())){
712 if (dst.getType() != src.getType()){
713 dst.reset(); // clear attributes, style, cstring and type.
714 // Warning: does not create links.
715 dst.setType(src.getType());
716 }
717 // dst.getAttributes().importMap(src.getAttributes());
718 MapTools::setValues(dst.getAttributes(), src.getAttributes());
719 dst.setStyle(src.getStyle());
720 // dst.setText(src.ctext); // wrong! set type to CTEXT
721 dst.ctext = src.ctext;
722 }
723
724 return dst;
725 }
726
727
728
729 /*
730 UNUSED!
731 template <typename T>
732 static
733 T & xmlGuessType(const typename T::node_data_t & parentNode, T & child){
734 typedef typename T::node_data_t::xml_default_elem_map_t map_t;
735 const typename map_t::const_iterator it = T::node_data_t::xml_default_elems.find(parentNode.getNativeType());
736 if (it != T::node_data_t::xml_default_elems.end()){
737 child->setType(it->second);
738 drain::Logger(__FILE__, __FUNCTION__).experimental<LOG_WARNING>("Default type set: ", child->getTag());
739 }
740 return child;
741 }
742 */
743
744
745
746};
747
748
749// template <> const drain::Enum<XML::entity_t>::dict_t drain::Enum<XML::entity_t>::dict;
750DRAIN_ENUM_DICT(XML::entity_t);
751DRAIN_ENUM_OSTREAM(XML::entity_t);
752
753// drain::UnorderedMultiTree<NodeSVG,false, NodeXML<>::path_t> TreeSVG;
754// , const std::string & defaultTag
755// template <class TR>
756template <class N>
757std::ostream & XML::toStream(std::ostream & ostr, const UnorderedMultiTree<N> & tree, int indent){
758
759 drain::Logger mout(__FILE__,__FUNCTION__);
760
761 typedef UnorderedMultiTree<N> TR;
762
763 const typename TR::container_t & children = tree.getChildren();
764
765 // const XML & data = tree.data; // template type forcing, keep here for programming aid.
766 const typename TR::node_data_t & data = tree.data; // template used
767
768 tag_display_mode mode = EMPTY_TAG;
769
770 if (data.isCText()){ // this can be true only at root, and rarely so...? (because recursive call not reached, if ctext)
771 data.nodeToStream(ostr, mode);
772 // ostr << "<!--TX-->";
773 return ostr;
774 }
775
776 if (!data.ctext.empty()){
777 // mout.warn("Non-CTEXT-elem with ctext: <", data.getTag(), " id='", data.getId(), "' ...>, text='", data.ctext, "'");
778 if (data.isSingular()){
779 // mout.warn("Skipping CTEXT of a singular element <", tree->getTag(), " id='", data.getId(), "' ...> , CTEXT: '", data.ctext, "'");
780 mode = EMPTY_TAG;
781 }
782 else {
783 mode = OPENING_TAG;
784 }
785 }
786
787 if (!children.empty()){
788 mode = OPENING_TAG;
789 if (data.isSingular()){
790 mout.warn("Singular (hence normally empty) element <", tree->getTag(), " id='", data.getId(), "' ...> has ", children.size(), " children?");
791 }
792 }
793
794 // mout.attention("Hey! ", TypeName<TR>::str(), " with ", TypeName<typename TR::node_data_t>::str(), "Explicit ", data.isExplicit(), " or implicit ", data.isSingular());
795 if (data.isExplicit()){ // explicit
796 mode = OPENING_TAG;
797 }
798 else if (data.isSingular()){ // <br/> <hr/>
799 mode = EMPTY_TAG;
800 }
801 // Hence, is flexible, "bimodal", supports empty and open-close mode.
802
803
804 // Indent
805 std::string fill(2*indent, ' ');
806 ostr << fill;
807
808 // Print opening tag and attributes.
809 data.nodeToStream(ostr, mode);
810
811 // Note: if tree has attributes, empty() == false.
812 //if (data.isScript() && !(tree.empty() && data.ctext.empty())){ // (mode==OPENING_TAG)
813 if (data.isScript() && (tree.hasChildren() || !data.ctext.empty())){
814 //std::string fill(2*indent, ' ');
815 ostr << "//<![CDATA[\n";
816 }
817
818 // TODO: consider unintended, "packed" class for TSPAN etc.
819
820 if (mode == EMPTY_TAG){
821 //ostr << "<!--ET-->";
822 ostr << '\n';
823 return ostr;
824 }
825 else if (data.isStyle()){
826 // https://www.w3.org/TR/xml/#sec-cdata-sect
827 // ostr << "<![CDATA[ \n";
828 // ostr << "<!-- STYLE -->"; WRONG!
829
830 if (!data.ctext.empty()){
831 // TODO: indent
832 ostr << fill << data.ctext;
833 StyleXML::commentToStream(ostr, " TEXT ");
834 ostr << '\n';
835 }
836
837 if (!data.getAttributes().empty()){
838 mout.warn("STYLE elem ", data.getId()," contains attributes, probably meant as style: ", sprinter(data.getAttributes()));
839 ostr << "\n\t /" << "* <!-- DISCARDED attribs ";
840 Sprinter::toStream(ostr, data.getAttributes()); //, StyleXML::styleRecordLayout
841 ostr << " /--> *" << "/" << '\n';
842 }
843
844 if (!data.style.empty()){
845 ostr << fill;
846 StyleXML::commentToStream(ostr, "STYLE OBJ");
847 ostr << '\n';
848 for (const auto & attr: data.style){
849 ostr << fill << " ";
850 Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
851 //attr.first << ':' attr.first << ':';
852 ostr << '\n';
853 }
854 // ostr << fill << "}\n";
855 // Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
856 // ostr << '\n';
857 }
858 ostr << '\n';
859
860 ostr << fill;
861 StyleXML::commentToStream(ostr, "style ELEMS");
862 ostr << '\n';
863
864 for (const auto & entry: tree.getChildren()){
865
866 if (entry.second->isComment()){
867 // StringTools::replace();
868 ostr << fill << "/* "<< entry.second->ctext << " */" << '\n';
869 // XML::toStream(ostr, entry.second, defaultTag, indent); // indent not used?
870 continue;
871 }
872
873 if (!entry.second->ctext.empty()){
874 //ostr << fill << "<!-- elem("<< entry.first << ") ctext /-->" << '\n';
875 ostr << fill << " " << entry.first << " {" << entry.second->ctext << "} /* CTEXT */ \n";
876 }
877
878 if (!entry.second->getAttributes().empty()){
879 ostr << fill << " " << entry.first << " {\n";
880 for (const auto & attr: entry.second->getAttributes()){
881 ostr << fill << " ";
882 if (attr.first == "id"){
883 StyleXML::commentToStream(ostr, "id=", attr.second);
884 // mout.suspicious("Style elem has id (", attr.second, ")");
885 }
886 else {
887 ostr << attr.first << ':' << attr.second << ';';
888 }
889 ostr << '\n';
890 }
891 ostr << fill << " }\n";
892 ostr << '\n';
893 }
894
895 }
896 ostr << "\n"; // end CTEXT
897 // ostr << " ]]>\n"; // end CTEXT
898 // end STYLE defs
899 ostr << fill;
900
901 }
902 else {
903
904 // Elements "own" CTEXT will be always output first -> check for problems, if other elements added first.
905 // ostr << data.ctext;
906 /*
907 if (data.isScript()){
908 ostr << data.ctext; // let < and > pass through
909 }
910 else {
911 ostr << data.ctext; // let < and > pass through
912 // StringTools::replace(XML::encodingMap, data.ctext, ostr); // sometimes an issue? // any time issue?
913 }
914 */
915 ostr << data.ctext;
916
917 // Detect if all the children are of type CTEXT, to be rendered in a single line.
918 // Note: potential re-parsing will probably detect them as a single CTEXT element.
919 bool ALL_CTEXT = true; // (!data.ctext.empty()) || !children.empty();
920
921 for (const auto & entry: children){
922 if (!entry.second->isCText()){
923 ALL_CTEXT = false;
924 break;
925 }
926 }
927
928 // ALL_CTEXT = false;
929
930 if (ALL_CTEXT){
931 // ostr << "<!--ALL_CTEXT-->";
932 char sep=0;
933 for (const auto & entry: children){
934 if (sep){
935 ostr << sep;
936 }
937 else {
938 sep = ' '; // consider global setting?
939 }
940 //ostr << entry.second->getText();
941 //StringTools::replace(XML::encodingMap, entry.second->getText(), ostr); // any time issue?
942 if (data.isScript()){
943 // Unfiltered
944 ostr << entry.second->getText();
945 }
946 else {
947 StringTools::replace(entry.second->getText(), getEntityMap(), ostr); // any time issue?
948 }
949 // ostr << entry.second->getText();
950 }
951 }
952 else {
953 // ostr << "<!-- RECURSION -->";
954 ostr << '\n';
956 for (const auto & entry: children){
957 //toStream(ostr, entry.second, entry.first, indent+1); // Notice, no ++indent
958 toStream(ostr, entry.second, indent+1); // Notice, no ++indent
959 // "implicit" newline
960 }
961 ostr << fill; // for CLOSING tag
962 }
963
964 }
965
966 // ostr << "<!-- END "<< data.getId() << ' ' << data.getTag() << '(' << data.getType() << ')' << "-->";
967 // Note: if tree has attributes, empty() == false.
968 if (data.isScript() && (tree.hasChildren() || !data.ctext.empty())){
969 // if (data.isScript() && !(tree.empty() && data.ctext.empty())){
970 ostr << '\n';
971 std::string fill(2*indent, ' ');
972 ostr << "//]]>";
973 }
974
975 data.nodeToStream(ostr, CLOSING_TAG);
976 ostr << '\n'; // Always after closing tag!
977
978 return ostr;
979}
980
981
982
983} // drain::
984
985#endif /* DRAIN_XML */
986
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 & reject(const TT &... args)
Some input has been rejected, for example by a syntax.
Definition Log.h:611
static void setValues(M &dst, const std::map< std::string, S > &srcMap)
Definition MapTools.h:213
static const M::mapped_type & get(const M &m, const typename M::key_type &key)
If the key is found, the value is returned as a reference.
Definition MapTools.h:92
ref_t & link(const std::string &key, F &x)
Associates a map entry with a variable.
Definition ReferenceMap.h:84
map_t::iterator iterator
Needed?
Definition SmartMap.h:80
static std::ostream & toStream(std::ostream &ostr, const std::initializer_list< T > &x, const SprinterLayout &layout=defaultLayout)
New (experimental)
Definition Sprinter.h:424
Definition StringBuilder.h:58
const std::string & str() const
For explicit string cast, esp. for (skipping) template deduction.
Definition StringBuilder.h:98
static void replace(const std::string &src, char search, char repl, std::ostream &ostr)
Replaces instances of 'search' to 'repl' in src.
Definition StringTools.cpp:94
static void commentToStream(std::ostream &ostr, const TT... args)
Practical utility, helps in adding C++ code commenting...
Definition StyleXML.h:72
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 const std::map< char, std::string > & getEntityMap()
Handy map for converting characters to XML entities. Example: '&' -> "&".
Definition XML.cpp:190
bool typeIs(const T2 &arg, const T3... args) const
Return true, if type is any of the arguments.
Definition XML.h:171
virtual bool isExplicit() const
Tell if this element should always have an explicit closing tag even when empty, like <STYLE></STYLE>
Definition XML.cpp:150
bool typeIsSet() const
Return true, if type is any of the arguments.
Definition XML.h:161
static const std::map< char, std::string > & getKeyConversionMap()
Characters that must be avoided in XML attribute keys: space, tab, =.
Definition XML.cpp:85
virtual bool isSingular() const
Tell if this element should always have an explicit closing tag even when empty, like <STYLE></STYLE>
Definition XML.cpp:144
void addClass(const TT &... args)
Style class.
Definition TreeXML.h:220
void setId()
Makes ID a visible attribute.
Definition XML.h:261
void setStyle(const std::string &key, const std::initializer_list< V > &l)
Set style of an element.
Definition XML.h:536
const std::string & getId() const
Returns ID of this element. Hopefully a unique ID...
Definition XML.h:283
virtual void setAttribute(const std::string &key, const char *value)
Default implementation. Needed for handling units in strings, like "50%" or "640px".
Definition XML.h:422
static const std::map< char, std::string > & getAttributeConversionMap()
Characters that must be avoided in XML attribute values: ".
Definition XML.cpp:100
void setAttribute(const std::string &key, const TT &... args)
"Final" implementation.
Definition XML.h:437
static const std::map< char, std::string > & getCTextConversionMap()
Characters to avoid in XML free text: <, >, {, },.
Definition XML.cpp:112
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:673
void setId(const TT &...args)
Concatenates arguments to an id.
Definition XML.h:276
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 std::ostream & toStream(std::ostream &ostr, const UnorderedMultiTree< N > &tree, int indent=0)
Definition XML.h:757
static N & xmlAssignNode(N &dst, const N &src)
Assign tree node (data) to another.
Definition XML.h:707
void reset()
Keep the element type but clear style, class and string data.
Definition XML.cpp:137
void setStyle(const std::string &key, const TT &... args)
For element/class/id, assign ...
Definition XML.h:567
virtual void setText(const std::string &s)
Assign the text content of this node. If the node type is undefined, set it to CTEXT.
Definition XML.cpp:155
void setComment(const T &...args)
Make this node a comment. Contained tree will not be deleted. In current version, attributes WILL be ...
Definition XML.h:295
XML()
User may optionally filter attributes and CTEST with this using StringTools::replace(XML::encodingMap...
Definition XML.h:127
virtual void setUrl(const std::string &s)
Definition XML.h:338
bool hasClass(const V &cls) const
Definition XML.h:614
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 XML.h:268
Definition DataSelector.cpp:1277
VariableT< VariableInitializer< ReferenceT< VariableBase > > > FlexibleVariable
Value container supporting dynamic type with own memory and optional linking (referencing) of externa...
Definition FlexibleVariable.h:67
Default implementation.
Definition TypeName.h:57