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
48
49namespace drain {
50
54template <class T=int>
55class NodeXML : public XML {
56
57public:
58
59 typedef T xml_tag_t;
60 typedef NodeXML<T> xml_node_t;
61 typedef drain::Path<std::string,'/'> path_t; // basically, also path_elem_t could be a template.
62 typedef UnorderedMultiTree<xml_node_t,false, path_t> xml_tree_t;
63
65
90 template <T ELEM>
91 class Elem; // {} ?
92
94 template <T ELEM>
95 friend class Elem;
96
97
99
102 inline
104 id = drain::StringBuilder<>('e', ++nextID);
105 // drain::StringTools::import(++nextID, id);
106 };
107
108 //
110
116 inline
117 NodeXML(const NodeXML & node){
118 drain::StringTools::import(++nextID, id);
119 // XML::xmlAssignNode(*this, node); // RISKY!? Should be called by the copy constructors of derived classes.
120 }
121
122 virtual inline
123 ~NodeXML(){};
124
125 // TODO: Shadowing. Check usage, change name no swapNode()
126 virtual
127 void swap(NodeXML<T> & node);
128
129
130 inline
131 T getNativeType() const {
132 return static_cast<T>(type); // may fail! consider two-way conversion assert
133 };
134
135public:
136
137 inline
138 void set(const NodeXML & node){
139 if (isUndefined()){
140 // Should make sense, and be safe. Esp. when exactly same node type, by templating
141 setType(node.getType());
142 }
143 else if (type == STYLE) {
144 drain::Logger mout(__FILE__, __FUNCTION__);
145 mout.suspicious("copying STYLE from node: ", node);
146 }
147 drain::MapTools::setValues<map_t>(getAttributes(), node.getAttributes());
148 }
149
150
151 inline
152 void set(const intval_t & type){
153 setType(type);
154 }
155
156
157 inline
158 void set(const std::string & s){
159 setText(s);
160 }
161
162 inline
163 void set(const char *s){
164 set(std::string(s));
165 }
166
167 inline
168 void set(const drain::Castable & s){
169 setText(s);
170 }
171
172
173 inline
174 //void set(const std::initializer_list<std::pair<const char *,const char *> > & args){
175 void set(const std::initializer_list<std::pair<const char *,const Variable> > & args){
176 // TODO: redirect to set(key,value), for consistency?
177 if (type == STYLE){
178 drain::Logger mout(__FILE__, __FUNCTION__);
179 mout.deprecating("Setting attributes/style of a STYLE element.");
180 setStyle(args);
181 /*
182 for (const auto & entry: l){
183 style[entry.first] = entry.second;
184 }
185 */
186 // drain::SmartMapTools::setValues(style, l);
187 }
188 else {
189 for (const auto & entry: args){
190 getAttributes()[entry.first] = entry.second;
191 }
193 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
194 }
195 }
196
197 template <class V>
198 inline
199 void set(const std::map<std::string, V> & args){
200 // TODO: redirect to set(key,value), for consistency
201 if (type == STYLE){
202 drain::Logger mout(__FILE__, __FUNCTION__);
203 mout.deprecating("Setting attributes/style of a STYLE element: "); //, args);
204 //drain::SmartMapTools::setValues(style, args);
205 setStyle(args);
206 /*
207 for (const auto & entry: args){
208 style[entry.first] = entry.second;
209 }
210 */
211 }
212 else {
213 drain::MapTools::setValues(getAttributes(), args); // add new keys
214 // drain::SmartMapTools::setValues<map_t,true>(getAttributes(), args); // add new keys
215 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
216 }
217 }
218
219
220 template <class V>
221 inline
222 void set(const std::string & key, const V & value){
223
224 // if (type == STYLE){
225 if (this->isStyle()){
226 // Modify collection directly
227 drain::Logger mout(__FILE__, __FUNCTION__);
228 // Well, this should actually be ok, as it is in the standard?
229 mout.deprecating("Setting style as attributes of a STYLE element: ", key, ':', value);
230 setStyle(key, value);
231 }
232 else if (key == "style"){
233 drain::Logger mout(__FILE__, __FUNCTION__);
234 mout.obsolete("Setting style as attribute: \"style\"=", value);
235 }
236 else if (key == "class"){
237 // mout.warn<LOG_DEBUG>("class");
238 std::string cls;
239 drain::StringTools::import(value, cls);
240 addClass(cls);
241 }
242 else {
243 setAttribute(key, value);
244 }
245
246 }
247
248
252 virtual
253 const std::string & getTag() const {
254 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::Enum<T>::dict) << std::endl; // <<
255 return drain::Enum<T>::getDict().getKey((T)type, false);
256 }
257
261 static inline // needed?
262 const std::string & getTag(const T & type){
263 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::Enum<T>::dict) << std::endl; // <<
264 return drain::Enum<T>::getDict().getKey((T)type, false);
265 }
266
267
268
269 inline
270 NodeXML & operator=(const NodeXML & node){
271 return XML::xmlAssignNode(*this, node);
272 }
273
274 // Check char *
275 inline
276 NodeXML & operator=(const xml_tag_t & x){ // needed? possibly with tree(int x) ?
277 //set(x);
278 setType(x);
279 return *this;
280 }
281
282 inline
283 NodeXML & operator=(const Castable &c){
284 setText(c);
285 return *this;
286 }
287
288
289 inline
290 NodeXML & operator=(const std::string &s){
291 setText(s);
292 return *this;
293 }
294
295 inline
296 NodeXML & operator=(const char *s){
297 setText(s);
298 return *this;
299 }
300
301 inline
302 NodeXML & operator=(const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
303 set(l);
304 return *this;
305 }
306
307
309 // std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const;
313 virtual
314 std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const override;
315
316
317 template <class V>
318 static inline
319 std::ostream & docToStream(std::ostream & ostr, const V & tree){
320 V::node_data_t::xml_node_t::docTypeToStream(ostr);
321 V::node_data_t::xml_node_t::toStream(ostr, tree);
322 // UtilsXML::toStream(ostr, tree);
323 return ostr;
324 }
325
326
328
340 static // virtual
341 inline
342 std::ostream & docTypeToStream(std::ostream &ostr){
343 ostr << "<?xml ";
344 for (const auto & entry: xmldoc_attribs){
345 xmlAttribToStream(ostr, entry.first, entry.second);
346 }
347 ostr << "?>";
348 ostr << '\n';
349 return ostr;
350 }
351
353 typedef std::map<xml_tag_t,xml_tag_t> xml_default_elem_map_t;
354 static const xml_default_elem_map_t xml_default_elems;
355
356protected:
357
359
362 //virtual
363 //void handleType(const T & type) = 0;
364 //void handleType() = 0;
365
366
368 typedef std::list<std::pair<std::string,std::string> > xmldoc_attrib_map_t;
369 static xmldoc_attrib_map_t xmldoc_attribs;
370
371
372};
373
374template <class T>
375void NodeXML<T>::swap(NodeXML<T> & node){
376 // Swap attributes
377 //ReferenceMap2<FlexibleVariable>::swap(node);
378 map_t::swap(node);
379 // Swap classes
380 this->classList.swap(node.classList);
381}
382
383
384
385/*
386 Impossible. Cannot construct final object, for example members are not available for #link() .
387template <>
388inline
389void NodeXML<int>::handle Type(const int & type){
390 // DANGER, without cast?
391 std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? " << type << '=' << std::endl;
392 std::cerr << __FILE__ << ':' << __FUNCTION__ << " dict: " << drain::sprinter(drain::Enum<int,XML>::dict) << std::endl;
393}
394*/
395
396template <>
397inline
398const std::string & NodeXML<int>::getTag() const {
399 return drain::Enum<int,XML>::dict.getKey(this->type, false);
400}
401
402typedef NodeXML<>::xml_tree_t TreeXML;
403//typedef drain::UnorderedMultiTree<NodeXML<>,false, NodeXML<>::path_t> TreeXML;
404
405// NOTE: template will not match for subclasses of NodeXML<E> because default template will match any class exactly.
406template <class E, bool EX, class P>
407struct TypeName< drain::UnorderedMultiTree<NodeXML<E>,EX,P> > {
408
409 static const std::string & str(){
410 static const std::string name = drain::StringBuilder<>("TreeXML<", TypeName<E>::str(), ">");
411 return name;
412 }
413
414};
415
416
417
418
419template <class N>
420std::ostream & NodeXML<N>::nodeToStream(std::ostream &ostr, tag_display_mode mode) const {
421
422
423 if (isCText()){
424 if (mode != CLOSING_TAG){ // or: OPENING
425 ostr << ctext; // << '(' << mode << ')'; // << " /-->\n";
426 }
427 return ostr;
428 }
429 else if (isComment()){
430 // Remember: a large subtree can be commented out
431 if (mode != CLOSING_TAG){
432 ostr << "<!--"; // << ctext; // << " /-->\n";
433 }
434 }
435 else if (isScopeJS()){
436 if (mode != CLOSING_TAG){
437 ostr << "{\n";
438 }
439 else {
440 //ostr << "}\n";
441 ostr << "\n}";
442 }
443 return ostr;
444 }
445 else {
446
447 /*
448 if (isUndefined()){
449 drain::Logger(__FILE__, __FUNCTION__).warn("Undefined TAG type for ", getName(), " ID=", getId(), " attr=", drain::sprinter(getAttributes()));
450 }
451 */
452
453 /*
454 if (getTag().empty()){
455 drain::Logger(__FILE__, __FUNCTION__).unimplemented<LOG_ERR>("defaultTag for type=", getType(), " requested by ID=", getId(), " attr=", drain::sprinter(getAttributes()));
456
457 ostr << "defaultTag"; // << ' '; FIX! getDefaultTag?
458 }*/
459 if (isUndefined() || getTag().empty()){
460 drain::Logger(__FILE__, __FUNCTION__).warn("Undefined TAG type for ", getName(), " ID=", getId(), " attr=", drain::sprinter(getAttributes()));
461 //if (mode != CLOSING_TAG){
462 ostr << "<!-- " << getTag() << " tag? " << ctext << " /-->";
463 //}
464 }
465 else {
466
467 if (mode==CLOSING_TAG){
468 ostr << "</";
469 }
470 else {
471 ostr << '<';
472 }
473
474 ostr << getTag(); // << ' ';
475 // TODO check GDAL XML
476 // if (!defaultTag.empty())
477 // attribToStream(ostr, "name", defaultTag);
478 }
479 }
480
481 if (mode != CLOSING_TAG){
482
483 if (typeIs(STYLE)){
484 // xmlAttribToStream(ostr, "data-mode", "experimental");
485 }
486 else { // if (!isCText())
487
488 specificAttributesToStream(ostr);
489
490 char sep=0;
491
492 // Iterate attributes - note: also for comment
493 /*
494 for (const auto & key: getAttributes().getKeyList()){
495 std::string v = get(key, "");
496 // Skip empties (so Sprinter::toStream not applicable)
497 if (!v.empty()){
498 xmlAttribToStream(ostr, key, v);
499 sep=' ';
500 }
501 }
502 */
503 for (const auto & entry: getMap()){
504 //std::string v = get(entry.first, std::string(""));
505 std::string v = get(entry.first, "");
506 // Skip empties (so Sprinter::toStream not applicable)
507 if (!v.empty()){
508 xmlAttribToStream(ostr, entry.first, v);
509 sep=' ';
510 }
511 }
512
513 // Handle CSS style separately
514 if (!style.empty()){
515 if (sep)
516 ostr << sep;
517 ostr << "style=\"";
518 Sprinter::sequenceToStream(ostr, style, StyleXML::styleLineLayout);
519 ostr << '"'; // << ' ';
520 }
521
522 /*
523 if (!ctext.empty()){
524 ostr << " "; // debugging
525 }
526 */
527 }
528
529 }
530
531 // END
532 if (isComment()){
533 ostr << ' '; // prefix for free ctext
534 if (mode != OPENING_TAG){
535 // it is EMPTY_TAG or CLOSING TAG
536 ostr << "/-->"; // \n
537 }
538 // warn if children?
539 }
540 else if (isUndefined() || getTag().empty()){
541 /*
542 ostr << ' '; // prefix for free ctext
543 if (mode != OPENING_TAG){
544 // it is EMPTY_TAG or CLOSING TAG
545 ostr << "<!-- end /-->"; // \n
546 }
547 */
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
580DRAIN_ENUM_DICT2(int,XML);
581
582
583
584template <class E, bool EX, class P>
585std::ostream & operator<<(std::ostream &ostr, const UnorderedMultiTree<NodeXML<E>,EX,P> & tree){
586 // DOC def? TODO: preamble/prologToStream()
587 NodeXML<E>::docTypeToStream(ostr); // must be member, to support virtual?
588 NodeXML<E>::toStream(ostr, tree, "");
589 return ostr;
590}
591
592
593
594} // drain::
595
597
618#define DRAIN_XML_DEFAULT_ELEMS(xml_tree) template <> const NodeXML<xml_tree::node_data_t::tag_t>::xml_default_elem_map_t NodeXML<xml_tree::node_data_t::tag_t>::xml_default_elems
619
621
638#define DRAIN_XML_DEFAULT_INIT(xml_tree) template <> inline void xml_tree::initChild(xml_tree & child) const { UtilsXML::initChildWithDefaultType(*this, child); }
639
641
655#define DRAIN_XML_EASY_TYPE(xml_tree) template <> template <> inline xml_tree & xml_tree::operator()(const xml_tree::node_data_t::tag_t & type){ return UtilsXML::setType(*this, type); }
656
658#define DRAIN_XML_ENUM_KEY(xml_tree, enum_type) template <> template <> inline const xml_tree::key_t & xml_tree::getKey(const enum_type & type){ return Enum<enum_type>::dict.getKey(type, false); }
659
660
661#endif /* DRAIN_TREE_XML */
662
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 & deprecating(const TT &... args)
Feature will be removed. Special type of Logger::note().
Definition Log.h:522
static void setValues(M &dst, const std::map< std::string, S > &srcMap)
Definition MapTools.h:213
A "handle" for specialized element classes, i.e. with members like width , height or radius .
Definition TreeXML.h:91
Definition TreeXML.h:341
static std::ostream & docTypeToStream(std::ostream &ostr)
Write the XML definition beginning any XML document.
Definition TreeXML.h:342
virtual const std::string & getTag() const
Definition TreeXML.h:253
std::list< std::pair< std::string, std::string > > xmldoc_attrib_map_t
Internal function called after setType()
Definition TreeXML.h:368
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:420
static const std::string & getTag(const T &type)
Definition TreeXML.h:262
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:353
NodeXML()
Default constructor.
Definition TreeXML.h:103
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:175
NodeXML(const NodeXML &node)
Copy constructor.
Definition TreeXML.h:117
Definition Path.h:137
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:672
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:706
Definition DataSelector.cpp:1277
A container for a static dictionary of enumeration values.
Definition Enum.h:51
static const std::string & getKey(const std::string &s, bool lenient=true)
Convenience for object.set(...) like commands.
Definition Enum.h:144