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; // "final"
60 //typedef T tag_t;
61 typedef NodeXML<T> xml_node_t;
62 typedef drain::Path<std::string,'/'> path_t; // basically, also path_elem_t could be a template.
63 typedef UnorderedMultiTree<xml_node_t,false, path_t> xml_tree_t;
64
66
91 template <T ELEM>
92 class Elem; // {} ?
93
95
99 template <T ELEM>
100 friend class Elem;
101
103 typedef std::map<xml_tag_t,xml_tag_t> xml_default_elem_map_t;
104
105 static const xml_default_elem_map_t xml_default_elems;
106
108
111 inline
113 // id = drain::StringBuilder<>('e', ++nextID);
114 };
115
116 //
118
124 inline
125 NodeXML(const NodeXML & node){
126 id = drain::StringBuilder<>(node.getTag(), ++nextID);
127 // drain::StringTools::import(++nextID, id);
128 // TODO: CHECK: XML::xmlAssignNode(*this, node); // RISKY!? Should be called by the copy constructors of derived classes.
129 }
130
131 virtual inline
132 ~NodeXML(){};
133
135
139 virtual inline
140 const std::string & getTag() const override {
141 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::Enum<T>::dict) << std::endl; // <<
142 return drain::Enum<T>::getDict().getKey((T)type, false);
143 }
144
148 static inline
149 const std::string & getTag(const T & type){
150 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::Enum<T>::dict) << std::endl; // <<
151 return drain::Enum<T>::getDict().getKey((T)type, false);
152 }
153
155
160 // virtual void swapNode(NodeXML<T> & node);
161
162
163 //
164 inline
165 T getNativeType() const {
166 return static_cast<T>(type); // may fail! consider two-way conversion assert
167 };
168
169
170 inline
171 void set(const NodeXML<T> & node){
172 if (isUndefined()){
173 // Should make sense, and be safe. Esp. when exactly same node type, by templating
174 setType(node.getType());
175 }
176 else if (type == STYLE) {
177 drain::Logger mout(__FILE__, __FUNCTION__);
178 mout.suspicious("copying STYLE from node: ", node);
179 }
180 drain::MapTools::setValues<map_t>(getAttributes(), node.getAttributes());
181 }
182
183
184 inline
185 void set(const intval_t & type){
186 setType(type);
187 }
188
189
190 inline
191 void set(const std::string & s){
192 setText(s);
193 }
194
195 inline
196 void set(const char *s){
197 set(std::string(s));
198 }
199
200 inline
201 void set(const drain::Castable & s){
202 setText(s);
203 }
204
205
206 inline
207 void set(const std::initializer_list<std::pair<const char *,const Variable> > & args){
208 // TODO: redirect to set(key,value), for consistency?
209 if (type == STYLE){
210 drain::Logger mout(__FILE__, __FUNCTION__);
211 mout.deprecating("Setting attributes/style of a STYLE element.");
212 setStyle(args);
213 /*
214 for (const auto & entry: l){
215 style[entry.first] = entry.second;
216 }
217 */
218 // drain::SmartMapTools::setValues(style, l);
219 }
220 else {
221 for (const auto & entry: args){
222 getAttributes()[entry.first] = entry.second;
223 }
225 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
226 }
227 }
228
229 template <class V>
230 inline
231 void set(const std::map<std::string, V> & args){
232 // TODO: redirect to set(key,value), for consistency
233 if (type == STYLE){
234 drain::Logger mout(__FILE__, __FUNCTION__);
235 mout.deprecating("Setting attributes/style of a STYLE element: "); //, args);
236 //drain::SmartMapTools::setValues(style, args);
237 setStyle(args);
238 /*
239 for (const auto & entry: args){
240 style[entry.first] = entry.second;
241 }
242 */
243 }
244 else {
245 drain::MapTools::setValues(getAttributes(), args); // add new keys
246 // drain::SmartMapTools::setValues<map_t,true>(getAttributes(), args); // add new keys
247 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
248 }
249 }
250
251
252 template <class V>
253 inline
254 void set(const std::string & key, const V & value){
255
256 if (this->isStyle()){
257 // Modify collection directly
258 drain::Logger mout(__FILE__, __FUNCTION__);
259 // Well, this should actually be ok, as it is in the standard?
260 mout.deprecating("Setting style as attributes of a STYLE element: ", key, ':', value);
261 setStyle(key, value);
262 }
263 else if (key == "style"){
264 drain::Logger mout(__FILE__, __FUNCTION__);
265 mout.obsolete("Setting style as attribute: \"style\"=", value);
266 }
267 else if (key == "class"){
268 // mout.warn<LOG_DEBUG>("class");
269 std::string cls;
270 drain::ClassXML xls;
271 drain::StringTools::import(value, cls); // Or Convert?
272 addClass(cls);
273 //drain::Logger(__FILE__, __FUNCTION__).revised("addClass:", value);
274 // addClass(value);
275 }
276 else {
277 setAttribute(key, value);
278 }
279
280 }
281
282
283
284
285
286 inline
287 NodeXML & operator=(const NodeXML & node){
288 return XML::xmlAssignNode(*this, node);
289 }
290
291 // Check char *
292 inline
293 NodeXML & operator=(const xml_tag_t & x){ // needed? possibly with tree(int x) ?
294 setType(x);
295 return *this;
296 }
297
298 inline
299 NodeXML & operator=(const Castable &c){
300 setText(c);
301 return *this;
302 }
303
304
305 inline
306 NodeXML & operator=(const std::string &s){
307 setText(s);
308 return *this;
309 }
310
311 inline
312 NodeXML & operator=(const char *s){
313 setText(s);
314 return *this;
315 }
316
317 inline
318 NodeXML & operator=(const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
319 set(l);
320 return *this;
321 }
322
323
325 // std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const;
329 virtual
330 std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const override;
331
332
333 template <class V>
334 static inline
335 std::ostream & docToStream(std::ostream & ostr, const V & tree){
336 V::node_data_t::xml_node_t::docTypeToStream(ostr);
337 V::node_data_t::xml_node_t::toStream(ostr, tree);
338 // UtilsXML::toStream(ostr, tree);
339 return ostr;
340 }
341
342
344
356 static // virtual
357 inline
358 std::ostream & docTypeToStream(std::ostream &ostr){
359 ostr << "<?xml ";
360 for (const auto & entry: xmldoc_attribs){
361 xmlAttribToStream(ostr, entry.first, entry.second);
362 }
363 ostr << "?>";
364 ostr << '\n';
365 return ostr;
366 }
367
368
369protected:
370
372 typedef std::list<std::pair<std::string,std::string> > xmldoc_attrib_map_t;
373 static xmldoc_attrib_map_t xmldoc_attribs;
374
375
376};
377
378
379
380
381
382/*
383template <>
384inline
385const std::string & NodeXML<int>::getTag() const {
386 return drain::Enum<int,XML>::dict.getKey(this->type, false);
387}
388*/
389#define DRAIN_XML_TREE(N) drain::UnorderedMultiTree<N,false, NodeXML<>::path_t>
390
391//typedef NodeXML<>::xml_tree_t TreeXML;
392typedef DRAIN_XML_TREE(NodeXML<>) TreeXML;
393
394//typedef drain::UnorderedMultiTree<NodeXML<>,false, NodeXML<>::path_t> TreeXML;
395//#define DRAIN_XML_TREE(N) NodeXML<N>::xml_tree_t
396
397// NOTE: template will not match for subclasses of NodeXML<E> because default template will match any class exactly.
398template <class E, bool EX, class P>
399struct TypeName< drain::UnorderedMultiTree<NodeXML<E>,EX,P> > {
400
401 static const std::string & str(){
402 static const std::string name = drain::StringBuilder<>("TreeXML<", TypeName<E>::str(), ">");
403 return name;
404 }
405
406};
407
408
409
410
411template <class N>
412std::ostream & NodeXML<N>::nodeToStream(std::ostream &ostr, tag_display_mode mode) const {
413
414
415 if (isCText()){
416 if (mode != CLOSING_TAG){ // or: OPENING
417 ostr << ctext; // << '(' << mode << ')'; // << " /-->\n";
418 }
419 return ostr;
420 }
421 else if (isComment()){
422 // Remember: a large subtree can be commented out
423 if (mode != CLOSING_TAG){
424 ostr << "<!--"; // << ctext; // << " /-->\n";
425 }
426 }
427 else if (isScopeJS()){
428 if (mode != CLOSING_TAG){
429 ostr << ctext << "{\n";
430 }
431 else {
432 // Newline good in avoiding potential comment line
433 ostr << "\n}";
434 }
435 // return ostr;
436 }
437 else {
438
439 /*
440 if (isUndefined()){
441 drain::Logger(__FILE__, __FUNCTION__).warn("Undefined TAG type for ", getName(), " ID=", getId(), " attr=", drain::sprinter(getAttributes()));
442 }
443 */
444
445 /*
446 if (getTag().empty()){
447 drain::Logger(__FILE__, __FUNCTION__).unimplemented<LOG_ERR>("defaultTag for type=", getType(), " requested by ID=", getId(), " attr=", drain::sprinter(getAttributes()));
448
449 ostr << "defaultTag"; // << ' '; FIX! getDefaultTag?
450 }*/
451 if (isUndefined() || getTag().empty()){
452 drain::Logger(__FILE__, __FUNCTION__).warn("Undefined TAG type for ", getName(), " ID=", getId(), " attr=", drain::sprinter(getAttributes()));
453 //if (mode != CLOSING_TAG){
454 ostr << "<!-- " << getTag() << " tag? " << ctext << " /-->";
455 //}
456 }
457 else {
458
459 if (mode==CLOSING_TAG){
460 ostr << "</";
461 }
462 else {
463 ostr << '<';
464 }
465
466 ostr << getTag(); // << ' ';
467 // TODO check GDAL XML
468 // if (!defaultTag.empty())
469 // attribToStream(ostr, "name", defaultTag);
470 }
471 }
472
473 if (mode != CLOSING_TAG){
474
475 if (typeIs(STYLE)){
476 // xmlAttribToStream(ostr, "data-mode", "experimental");
477 }
478 else { // if (!isCText())
479
480 specificAttributesToStream(ostr);
481
482 char sep=0;
483
484 // Iterate attributes - note: also for comment
485 /*
486 for (const auto & key: getAttributes().getKeyList()){
487 std::string v = get(key, "");
488 // Skip empties (so Sprinter::toStream not applicable)
489 if (!v.empty()){
490 xmlAttribToStream(ostr, key, v);
491 sep=' ';
492 }
493 }
494 */
495 for (const auto & entry: getMap()){
496 //std::string v = get(entry.first, std::string(""));
497 std::string v = getAttribute(entry.first, "");
498 // Skip empties (so Sprinter::toStream not applicable)
499 if (!v.empty()){
500 xmlAttribToStream(ostr, entry.first, v);
501 sep=' ';
502 }
503 }
504
505 // Handle CSS style separately
506 if (!style.empty()){
507 if (sep)
508 ostr << sep;
509 ostr << "style=\"";
510 Sprinter::sequenceToStream(ostr, style, StyleXML::styleLineLayout);
511 ostr << '"'; // << ' ';
512 }
513
514 /*
515 if (!ctext.empty()){
516 ostr << " "; // debugging
517 }
518 */
519 }
520
521 }
522
523 // END
524 if (isComment()){
525 ostr << ' '; // prefix for free ctext
526 if (mode != OPENING_TAG){
527 // it is EMPTY_TAG or CLOSING TAG
528 ostr << "/-->"; // \n
529 }
530 // warn if children?
531 }
532 else if (isUndefined() || getTag().empty()){
533 /*
534 ostr << ' '; // prefix for free ctext
535 if (mode != OPENING_TAG){
536 // it is EMPTY_TAG or CLOSING TAG
537 ostr << "<!-- end /-->"; // \n
538 }
539 */
540 }
541 else if (mode==EMPTY_TAG){ // OR no ctext!
542 if (isScopeJS()){
543 ostr << "}";
544 }
545 else {
546 // close TAG
547 ostr << "/>"; // \n <- check newline - add before indent?
548 }
549 }
550 else {
551 ostr << ">";
552 }
553
554 return ostr;
555
556}
557
558
559template <class N>
560inline
561std::ostream & operator<<(std::ostream &ostr, const NodeXML<N> & node){
562 return node.nodeToStream(ostr);
563}
564
565// XML output function shared for all XML documents, ie versions defined in subclasses.
566// TODO: preamble/prologToStream()
567// TODO: CHECK: previously documented parameter 'defaultTag' - important for - no longer attached to any function; reconsider or remove.
568
573DRAIN_ENUM_DICT2(int,XML);
574
575
576
577template <class E, bool EX, class P>
578std::ostream & operator<<(std::ostream &ostr, const UnorderedMultiTree<NodeXML<E>,EX,P> & tree){
579 // DOC def? TODO: preamble/prologToStream()
580 NodeXML<E>::docTypeToStream(ostr); // must be member, to support virtual?
581 NodeXML<E>::toStream(ostr, tree, "");
582 return ostr;
583}
584
585
586
587} // drain::
588
590
611#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
612
613
615#define DRAIN_GETKEY_ENUM(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); }
616
617
618#endif /* DRAIN_TREE_XML */
619
Definition Castable.h:76
A wrapper marking string an CSS effect.
Definition ClassXML.h:57
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:326
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:440
Logger & deprecating(const TT &... args)
Feature will be removed. Special type of Logger::note().
Definition Log.h:531
static void setValues(M &dst, const std::map< std::string, S > &srcMap)
Definition MapTools.h:211
A "handle" for specialized element classes, i.e. with members like width , height or radius .
Definition TreeXML.h:92
Definition TreeXML.h:55
static std::ostream & docTypeToStream(std::ostream &ostr)
Write the XML definition beginning any XML document.
Definition TreeXML.h:358
std::list< std::pair< std::string, std::string > > xmldoc_attrib_map_t
Control constant variables of (note: templated, through Node<T>::)
Definition TreeXML.h:372
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:412
virtual const std::string & getTag() const override
Default implementation of tag name retrieval based on drain::Enum<t>.
Definition TreeXML.h:140
static const std::string & getTag(const T &type)
Definition TreeXML.h:149
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:103
NodeXML()
Default constructor.
Definition TreeXML.h:112
T getNativeType() const
Change attributes, styles and classes of a node.
Definition TreeXML.h:165
void set(const std::initializer_list< std::pair< const char *, const Variable > > &args)
Definition TreeXML.h:207
NodeXML(const NodeXML &node)
Copy constructor.
Definition TreeXML.h:125
Definition Path.h:135
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:324
Definition StringBuilder.h:58
Base class for XML "nodes", to be data elements T for drain::Tree<T>
Definition XML.h:69
int intval_t
Definition XML.h:81
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:853
virtual void setAttribute(const std::string &key, const std::string &value)
Default implementation. Needed for handling units in strings, like "50%" or "640px".
Definition XML.h:556
static std::ostream & toStream(std::ostream &ostr, const UnorderedMultiTree< N > &tree, int indent=0)
Definition XML.h:1065
void setType(const T &t)
Definition XML.h:200
static N & xmlAssignNode(N &dst, const N &src)
Assign tree node (data) to another.
Definition XML.h:887
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:204
Definition Data.h:1473
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
Default implementation.
Definition TypeName.h:54
static const std::string & str()
Default implementation: name returned by std::type_info::name()
Definition TypeName.h:68