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#include "UtilsXML.h"
48
49
50namespace drain {
51
52
56template <class T=int>
57class NodeXML : public XML {
58
59public:
60
61 typedef T xml_tag_t;
62 typedef NodeXML<T> xml_node_t;
63 typedef drain::Path<std::string,'/'> path_t; // basically, also path_elem_t could be a template.
64 typedef UnorderedMultiTree<xml_node_t,false, path_t> xml_tree_t;
65
66 inline
67 NodeXML(const intval_t & t = intval_t(0)){
68 setType(t);
69 drain::StringTools::import(++nextID, id);
70 };
71
72 // Note: use default constructor in derived classes.
73 inline
74 NodeXML(const NodeXML & node){
75 XML::xmlAssignNode(*this, node);
76 drain::StringTools::import(++nextID, id);
77 }
78
79 inline
80 ~NodeXML(){};
81
82
83 template <class T2> // "final"
84 void setType(const T2 &t){ // DANGER, without cast?
85 type = static_cast<intval_t>(t); // (elem_t)
86 handleType(static_cast<T>(t));
87 // in derived classes, eg. drain::image::BaseGDAL
88 // warning: case value ‘...’ not in enumerated type
89 }
90
91 /* Consider this later, for user-defined (not enumerated) tag types.
92 virtual
93 void setType(const std::string & type);
94 */
95
96 inline
97 const intval_t & getType() const {
98 return type;
99 };
100
101 inline
102 T getNativeType() const {
103 return static_cast<T>(type); // may fail! consider two-way conversion assert
104 };
105
106
107public:
108
109
110
114 virtual
115 const std::string & getTag() const {
116 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::EnumDict<T>::dict) << std::endl; // <<
117 return drain::EnumDict<T>::getDict().getKey((T)type, false);
118 }
119
123 static inline // needed?
124 const std::string & getTag(const T & type){
125 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::EnumDict<T>::dict) << std::endl; // <<
126 return drain::EnumDict<T>::getDict().getKey((T)type, false);
127 }
128
129
130 inline
131 void set(const NodeXML & node){
132 if (isUndefined()){
133 // Should make sense, and be safe. Esp. when exactly same node type, by templating
134 setType(node.getType());
135 }
136 else if (type == STYLE) {
137 drain::Logger mout(__FILE__, __FUNCTION__);
138 mout.suspicious("copying STYLE from node: ", node);
139 }
140 drain::SmartMapTools::setValues<map_t>(getAttributes(), node.getAttributes());
141 }
142
143 inline
144 void set(const intval_t & type){
145 setType(type);
146 }
147
148 inline
149 void set(const std::string & s){
150 setText(s);
151 }
152
153 inline
154 void set(const char *s){
155 set(std::string(s));
156 }
157
158 inline
159 void set(const drain::Castable & s){
160 setText(s);
161 }
162
163 /*
164 inline
165 void set(const std::initializer_list<Variable::init_pair_t > &l){
166 // TODO: redirect to set(key,value), for consistency
167 if (type == STYLE){
168 drain::SmartMapTools::setValues(style, l);
169 }
170 else {
171 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), l); // add new keys
172 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
173 }
174 }
175 */
176
177 inline
178 //void set(const std::initializer_list<std::pair<const char *,const char *> > & args){
179 void set(const std::initializer_list<std::pair<const char *,const Variable> > & args){
180 // TODO: redirect to set(key,value), for consistency?
181 if (type == STYLE){
182 drain::Logger mout(__FILE__, __FUNCTION__);
183 mout.deprecating("Setting attributes/style of a STYLE element.");
184 setStyle(args);
185 /*
186 for (const auto & entry: l){
187 style[entry.first] = entry.second;
188 }
189 */
190 // drain::SmartMapTools::setValues(style, l);
191 }
192 else {
193 for (const auto & entry: args){
194 getAttributes()[entry.first] = entry.second;
195 }
197 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
198 }
199 }
200
201 template <class V>
202 inline
203 void set(const std::map<std::string, V> & args){
204 // TODO: redirect to set(key,value), for consistency
205 if (type == STYLE){
206 drain::Logger mout(__FILE__, __FUNCTION__);
207 mout.deprecating("Setting attributes/style of a STYLE element: ", args);
208 //drain::SmartMapTools::setValues(style, args);
209 setStyle(args);
210 /*
211 for (const auto & entry: args){
212 style[entry.first] = entry.second;
213 }
214 */
215 }
216 else {
217 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), args); // add new keys
218 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
219 }
220 }
221
222
223 template <class V>
224 inline
225 void set(const std::string & key, const V & value){
226 if (type == STYLE){
227 // Modify collection directly
228 drain::Logger mout(__FILE__, __FUNCTION__);
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 inline
249 NodeXML & operator=(const NodeXML & node){
250 return XML::xmlAssignNode(*this, node);
251 }
252
253 // Check char *
254 inline
255 NodeXML & operator=(const xml_tag_t & x){ // needed? possibly with tree(int x) ?
256 //set(x);
257 setType(x);
258 return *this;
259 }
260
261 inline
262 NodeXML & operator=(const Castable &c){
263 setText(c);
264 return *this;
265 }
266
267
268 inline
269 NodeXML & operator=(const std::string &s){
270 setText(s);
271 return *this;
272 }
273
274 inline
275 NodeXML & operator=(const char *s){
276 setText(s);
277 return *this;
278 }
279
280 inline
281 NodeXML & operator=(const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
282 set(l);
283 return *this;
284 }
285
286
288 // std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const;
292 virtual
293 std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const;
294
295
296
297 template <class V>
298 static inline
299 std::ostream & docToStream(std::ostream & ostr, const V & tree){
300 V::node_data_t::xml_node_t::docTypeToStream(ostr);
301 V::node_data_t::xml_node_t::toStream(ostr, tree);
302 // UtilsXML::toStream(ostr, tree);
303 return ostr;
304 }
305
306
308
320 static // virtual
321 inline
322 std::ostream & docTypeToStream(std::ostream &ostr){
323 ostr << "<?xml ";
324 for (const auto & entry: xmldoc_attribs){
325 xmlAttribToStream(ostr, entry.first, entry.second);
326 }
327 ostr << "?>";
328 ostr << '\n';
329 return ostr;
330 }
331
332 // drain::NodeHTML::HTML
333 // typedef std::pair<key_t,xml_node_t> node_pair_t;
334 // TODO: where is this needed?
335 /*
336 template <int E>
337 static inline
338 const std::pair<key_t,NodeXML<intval_t> > & entry(){
339 static const intval_t elem = (intval_t)E;
340 static const std::pair<key_t,NodeXML<intval_t> > nodeEntry(getTag(E), elem); // note: converts tag (string) to key_t if needed.
341 return nodeEntry;
342 }
343 */
344
345 typedef std::map<xml_tag_t,xml_tag_t> xml_default_elem_map_t;
346 static const xml_default_elem_map_t xml_default_elems;
347
348protected:
349
351
354 virtual inline
355 void handleType(const T & type){
356 if ((int)type != 0){
357 drain::Logger(__FILE__, __FUNCTION__).reject("handleType( ", (int)type, " ) - this is available only as specialized, by inherited classed like SVG, HTML?");
358 }
359 // DANGER, without cast?
360 // std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? " << type << '=' << std::endl;
361 // std::cerr << __FILE__ << ':' << __FUNCTION__ << " dict: " << drain::sprinter(drain::EnumDict<T>::dict) << std::endl;
362 }
363
364
366 //typedef std::map<std::string,std::string> xmldoc_attrib_map_t;
367 typedef std::list<std::pair<std::string,std::string> > xmldoc_attrib_map_t;
368 static xmldoc_attrib_map_t xmldoc_attribs;
369
370
371};
372
373/*
374 Impossible. Cannot construct final object, for example members are not available for #link() .
375template <>
376inline
377void NodeXML<int>::handle Type(const int & type){
378 // DANGER, without cast?
379 std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? " << type << '=' << std::endl;
380 std::cerr << __FILE__ << ':' << __FUNCTION__ << " dict: " << drain::sprinter(drain::EnumDict<int,XML>::dict) << std::endl;
381}
382*/
383
384template <>
385inline
386const std::string & NodeXML<int>::getTag() const {
387 return drain::EnumDict<int,XML>::dict.getKey(this->type, false);
388}
389
390typedef NodeXML<>::xml_tree_t TreeXML;
391//typedef drain::UnorderedMultiTree<NodeXML<>,false, NodeXML<>::path_t> TreeXML;
392
393// NOTE: template will not match for subclasses of NodeXML<E> because default template will match any class exactly.
394template <class E, bool EX, class P>
395struct TypeName< drain::UnorderedMultiTree<NodeXML<E>,EX,P> > {
396
397 static const std::string & str(){
398 static const std::string name = drain::StringBuilder<>("TreeXML<", TypeName<E>::str(), ">");
399 return name;
400 }
401
402};
403
404/* This could be it, unless already defined...
405template <class N, bool EX, class P>
406inline
407drain::UnorderedMultiTree<N,EX,P> & drain::UnorderedMultiTree<N,EX,P>::addChild(const drain::UnorderedMultiTree<N,EX,P>::key_t & key){
408 return XML::xmlAddChild(*this, key);
409}
410*/
411
412/* doesnt work
413template <class E, bool EX, class P>
414inline
415drain::UnorderedMultiTree<NodeXML<E>,EX,P> & drain::UnorderedMultiTree<NodeXML<E>,EX,P>::addChild(const std::string & key){
416 return XML::xmlAddChild(*this, key);
417}
418*/
419
420/*
421template <class N, bool EX, class P>
422template <typename K> // for K (path elem arg)
423const typename drain::UnorderedMultiTree<N,EX,P>::key_t & drain::UnorderedMultiTree<N,EX,P>::getKey(const K & key){
424 return drain::EnumDict<K>::dict.getKey(key, false);
425}
426*/
427
428
429
430template <class N>
431std::ostream & NodeXML<N>::nodeToStream(std::ostream &ostr, tag_display_mode mode) const {
432
433
434 if (isCText()){
435 if (mode != CLOSING_TAG){ // or: OPENING
436 ostr << ctext; // << '(' << mode << ')'; // << " /-->\n";
437 }
438 return ostr;
439 }
440 else if (isComment()){
441 // Remember: a large subtree can be commented out
442 if (mode != CLOSING_TAG){
443 ostr << "<!--"; // << ctext; // << " /-->\n";
444 }
445 }
446 else {
447
448 if (mode==CLOSING_TAG){
449 ostr << "</";
450 }
451 else {
452 ostr << '<';
453 }
454
455 if (getTag().empty()){
456 drain::Logger(__FILE__, __FUNCTION__).unimplemented<LOG_ERR>("defaultTag for type=", getType(), " requested by for ID=", getId(), " attr=", getAttributes());
457
458 ostr << "defaultTag"; // << ' '; FIX! getDefaultTag?
459 }
460 else {
461 ostr << getTag(); // << ' ';
462 // TODO check GDAL XML
463 // if (!defaultTag.empty())
464 // attribToStream(ostr, "name", defaultTag);
465 }
466 }
467
468 if (mode != CLOSING_TAG){
469
470 if (typeIs(STYLE)){
471 // xmlAttribToStream(ostr, "data-mode", "experimental");
472 }
473 else { // if (!isCText())
474
475 specificAttributesToStream(ostr);
476
477 char sep=0;
478
479 // Iterate attributes - note: also for comment
480 for (const auto & key: getAttributes().getKeyList()){
481 std::string v = get(key, "");
482 // Skip empties (so Sprinter::toStream not applicable)
483 if (!v.empty()){
484 xmlAttribToStream(ostr, key, v);
485 sep=' ';
486 }
487 }
488
489 // Handle CSS style separately
490 if (!style.empty()){
491 if (sep)
492 ostr << sep;
493 ostr << "style=\"";
494 Sprinter::sequenceToStream(ostr, style, StyleXML::styleLineLayout);
495 ostr << '"'; // << ' ';
496 }
497
498 /*
499 if (!ctext.empty()){
500 ostr << " "; // debugging
501 }
502 */
503 }
504
505 }
506
507 // END
508 if (isComment()){
509 ostr << ' '; // prefix for free ctext
510 if (mode != OPENING_TAG){
511 // it is EMPTY_TAG or CLOSING TAG
512 ostr << "/-->"; // \n
513 }
514 // warn if has children? or comment them??
515 }
516 else if (mode==EMPTY_TAG){ // OR no ctext!
517 // close TAG
518 ostr << "/>"; // \n <- check newline - add before indent?
519 }
520 else {
521 ostr << ">";
522 }
523
524 return ostr;
525
526}
527
528
529template <class N>
530inline
531std::ostream & operator<<(std::ostream &ostr, const NodeXML<N> & node){
532 return node.nodeToStream(ostr);
533}
534
536
543template <>
545
546
547template <class E, bool EX, class P>
548std::ostream & operator<<(std::ostream &ostr, const UnorderedMultiTree<NodeXML<E>,EX,P> & tree){
549 // DOC def? TODO: preamble/prologToStream()
550 NodeXML<E>::docTypeToStream(ostr); // must be member, to support virtual?
551 NodeXML<E>::toStream(ostr, tree, "");
552 return ostr;
553}
554
555
556
557/*
558inline
559std::ostream & operator<<(std::ostream &ostr, const TreeXML & t){
560 // DOC def? TODO: preamble/prologToStream()
561 TreeXML::node_data_t::docTypeToStream(ostr); // must be member, to support virtual?
562 TreeXML::node_data_t::toStream(ostr, t, "");
563 return ostr;
564}
565*/
566
567
568} // drain::
569
570#endif /* TREEXML_H_ */
571
Definition Castable.h:76
Two-way mapping between strings and objects of template class T.
Definition Dictionary.h:63
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:312
Logger & reject(const TT &... args)
Some input has been rejected, for example by a syntax.
Definition Log.h:610
Logger & unimplemented(const TT &... args)
Feature to be done. Special type of Logger::note().
Definition Log.h:511
Logger & deprecating(const TT &... args)
Feature will be removed. Special type of Logger::note().
Definition Log.h:521
Definition TreeXML.h:341
static std::ostream & docTypeToStream(std::ostream &ostr)
Write the XML definition beginning any XML document.
Definition TreeXML.h:322
virtual const std::string & getTag() const
Definition TreeXML.h:115
std::list< std::pair< std::string, std::string > > xmldoc_attrib_map_t
NOTE: these could/should be templated, in TreeXML<...> right?
Definition TreeXML.h:367
virtual void handleType(const T &type)
Internal function called after setType()
Definition TreeXML.h:355
virtual std::ostream & nodeToStream(std::ostream &ostr, tag_display_mode mode=EMPTY_TAG) const
Dumps info. Future option: outputs leading and ending tag.
Definition TreeXML.h:431
static const std::string & getTag(const T &type)
Definition TreeXML.h:124
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 set(const std::initializer_list< std::pair< const char *, const Variable > > &args)
Definition TreeXML.h:179
Definition Path.h:112
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
void addClass(const TT &... args)
Style class.
Definition TreeXML.h:220
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 X & xmlAssignNode(X &dst, const X &src)
Assign another tree structure to another.
Definition XML.h:554
Definition DataSelector.cpp:1277
Wrapper for unique (static) dictionary of enum values.
Definition EnumFlags.h:66
static const std::string name
Default implementation: name returned by std::type_info::name()
Definition Type.h:558