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