XML.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25  */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood 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/Sprinter.h>
46 #include <drain/FlexibleVariable.h>
47 
48 #include "ClassXML.h"
49 // #include "UtilsXML.h"
50 // #include "Flags.h"
51 #include "ReferenceMap.h"
52 
53 namespace drain {
54 
55 
60 class StyleXML : public ReferenceMap2<FlexibleVariable> {
61 
62 public:
63 
64  inline
65  StyleXML(){};
66 
67  static const SprinterLayout styleLineLayout;
68  static const SprinterLayout styleRecordLayout;
69  static const SprinterLayout styleRecordLayoutActual;
70 
71 
72 };
73 
74 
75 inline
76 std::ostream & operator<<(std::ostream &ostr, const StyleXML & style){
78  return ostr;
79 }
80 
81 // ------------------------- public UtilsXML,
82 
83 class XML : protected ReferenceMap2<FlexibleVariable> {
84 public:
85 
86  typedef int intval_t;
87 
88  // TODO:
89  // static const intval_t flag_OPEN = 128;
90  // static const intval_t flag_TEXT = 256;
91 
92  static const intval_t UNDEFINED = 0;
93  static const intval_t COMMENT = 1; // || flag_TEXT
94  static const intval_t CTEXT = 2; // || flag_TEXT
95  static const intval_t SCRIPT = 3; // || flag_EXPLICIT || flag_TEXT
96  static const intval_t STYLE = 4; // || flag_EXPLICIT
97  static const intval_t STYLE_SELECT = 5;
98 
99 
100  intval_t type = XML::UNDEFINED;
101 
102  typedef ReferenceMap2<FlexibleVariable> map_t;
103 
105 
106  // String, still easily allowing numbers through set("id", ...)
107  std::string id;
108 
109  // Consider either/or
110  std::string ctext;
111 
112  std::string url;
113 
114  // Could be templated, behind Static?
115  static int nextID;
116 
117  inline
118  static int getCount(){
119  return nextID;
120  }
121 
123 
127  virtual
128  void clear();
129 
131 
135  inline
136  void reset(){
137  clear();
138  type = UNDEFINED;
139  }
140 
142 
145  inline
146  void setId(){
147  link("id", id);
148  }
149 
151  inline
152  void setId(const std::string & s){
153  link("id", id = s);
154  }
155 
157  template <char C='\0', typename ...TT>
158  inline
159  void setId(const TT & ...args) {
160  link("id", id = drain::StringBuilder<C>(args...));
161  }
162 
164  inline
165  const std::string & getId() const {
166  return id;
167  }
168 
169 
171 
175  template <class ...T>
176  inline
177  void setComment(const T & ...args) {
178  this->clear(); // what if also uncommenting needed?
179  // this->clearClasses();
180  type = COMMENT;
181  setText(args...);
182  }
183 
185 
190  void setText(const std::string & s);
191 
192  template <class ...T>
193  void setText(const T & ...args) {
194  setText(StringBuilder<>(args...).str()); // str() to avoid infinite loop
195  }
196 
197  inline
198  void setUrl(const std::string & s){
199  url = s;
200  }
201 
202  template <class ...T>
203  inline
204  void setName(const T & ...args){
205  setAttribute("data-name", drain::StringBuilder<>(args...));
206  }
207 
208 
209  // ---------------- Attributes ---------------
210 
211  virtual inline // shadows - consider virtual
212  bool empty() const {
213  return map_t::empty();
214  }
215 
216  inline
217  const map_t & getAttributes() const {
218  return *this;
219  };
220 
221  // Maybe controversial. Helps importing sets of variables.
222  inline
223  map_t & getAttributes(){
224  return *this;
225  };
226 
227  // Rename getAttribute?
228  inline
229  const drain::FlexibleVariable & get(const std::string & key) const {
230  return (*this)[key];
231  }
232 
233  // Rename getAttribute?
234  inline
235  drain::FlexibleVariable & get(const std::string & key){
236  return (*this)[key];
237  }
238 
239 
240  // Rename getAttribute?
241  template <class V>
242  inline
243  V get(const std::string & key, const V & defaultValue) const {
244  return map_t::get(key, defaultValue);
245  }
246 
247  inline
248  std::string get(const std::string & key, const char * defaultValue) const {
249  return map_t::get(key, defaultValue);
250  }
251 
253  // But otherways confusing?
254  virtual inline
255  void setAttribute(const std::string & key, const std::string &value){
256  (*this)[key] = value;
257  }
258 
260  // But otherways confusing?
261  virtual inline
262  void setAttribute(const std::string & key, const char *value){
263  (*this)[key] = value; // -> handleString()
264  }
265 
267  template <class V>
268  inline
269  void setAttribute(const std::string & key, const V & value){
270  (*this)[key] = value; // -> handleString()
271  }
272 
273 
274  inline
275  void removeAttribute(const std::string & s){
276  iterator it = this->find(s);
277  if (it != this->end()){
278  this->erase(it);
279  }
280  }
281 
282 
283  // ------------------ Style ---------------
284 
285 protected:
286 
287  StyleXML style;
288 
289 public:
290 
291  inline
292  const StyleXML & getStyle() const {
293  return style;
294  }
295 
296  inline
297  void setStyle(const StyleXML & s){
298  style.clear();
299  SmartMapTools::setValues(style, s);
300  }
301 
302  void setStyle(const std::string & value){
303  drain::Logger mout(__FILE__, __FUNCTION__);
304  if (type == UNDEFINED){
305  mout.reject<LOG_WARNING>("setting style for UNDEFINED elem: ", value);
306  mout.unimplemented<LOG_WARNING>("future option: set type to STYLE_SELECT");
307  }
308  else if (type == STYLE){
309  mout.reject<LOG_WARNING>("not setting style for STYLE elem: ", value); // , *this);
310  }
311  else {
312  SmartMapTools::setValues(style, value, ';', ':', "; \t\n"); // sep, equal, trim (also ';' ?)
313  }
314  }
315 
316  inline
317  void setStyle(const char *value){
318  setStyle(std::string(value));
319  }
320 
321  inline
322  void setStyle(const std::string & key, const std::string & value){
323  drain::Logger mout(__FILE__, __FUNCTION__);
324  if (type == UNDEFINED){
325  mout.reject<LOG_WARNING>("setting style for UNDEFINED elem: ", key, '=', value);
326  mout.unimplemented<LOG_WARNING>("future option: set type to STYLE_SELECT");
327  }
328  else if (type == STYLE){
329  mout.reject<LOG_WARNING>("not setting style for STYLE elem: ", value); // , *this);
330  }
331  else {
332  this->style[key] = value;
333  }
334  }
335 
336 
338 
344  template <class V>
345  inline
346  void setStyle(const std::string & key, const std::initializer_list<V> &l){
347  // const std::initializer_list<Variable::init_pair_t > &l
348  if (type == STYLE){ // typeIs(STYLE) fails
349  drain::Logger mout(__FILE__, __FUNCTION__);
350  mout.warn("Setting style of STYLE? initializer_list<", drain::TypeName<V>::str(), "> = ", sprinter(l)); // , StyleXML::styleLineLayout ?
351  }
352  this->style[key] = l;
353  }
354 
355 
357 
360  template <class V>
361  inline
362  void setStyle(const std::string & key, const V & value){
363 
364  if (type == STYLE){
365  drain::Logger(__FILE__, __FUNCTION__).reject<LOG_WARNING>("Setting style of STYLE: ", key, "=", value);
366  }
367  else {
368  this->style[key] = value;
369  }
370  }
371 
372  /*
373  template <typename K, typename V>
374  inline
375  void setStyle(const std::initializer_list<std::pair<K,V> > &args){
376  drain::SmartMapTools::setValues(style, args);
377  }
378  */
379 
380  inline
381  void setStyle(const std::initializer_list<std::pair<const char *,const drain::Variable> > &args){
382  drain::SmartMapTools::setValues(style, args);
383  }
384 
385  /*
386  inline
387  void setStyle( const std::initializer_list<std::pair<const char *,const char *> > & args){
388  drain::SmartMapTools::setValues(style, args);
389  }
390  */
391 
392  /*
393  template <class S>
394  inline
395  void setStyle(const S &value){
396  drain::Logger mout(__FILE__, __FUNCTION__);
397  mout.error("unsupported type ", drain::TypeName<S>::str(), " for value: ", typeid(value));
398  }
399  */
400 
401 
402 protected:
403 
404  // ------------------ Style Class ---------------
405 
406  ClassListXML classList;
407 
408 public:
409 
410  const ClassListXML & getClasses() const {
411  return classList;
412  }
413 
414  template <typename ... TT>
415  inline
416  void addClass(const TT &... args) {
417  classList.add(args...);
418  }
419 
423  template <class V>
424  inline
425  bool hasClass(const V & cls) const {
426  return classList.has(cls);
427  }
428 
429  inline
430  void removeClass(const std::string & s) {
431  classList.remove(s);
432  }
433 
434  inline
435  void clearClasses(){
436  classList.clear();
437  }
438 
439 
440  virtual
441  void specificAttributesToStream(std::ostream & ostr) const;
442 
443 
444 // ----------------- Static utilities for derived classes ----------------------
445 
446  template <class V>
447  static inline
448  void xmlAttribToStream(std::ostream &ostr, const std::string & key, const V &value){
449  ostr << ' ' << key << '=' << '"' << value << '"'; // << ' ';
450  }
451 
453 
456  template <typename TX>
457  static inline
458  TX & xmlAssign(TX & dst, const TX & src){
459 
460  if (&src != &dst){
461  dst.clear();
462  // also dst->clear();
463  dst->setType(src->getType());
464  dst->ctext = src->ctext;
465  dst->getAttributes() = src->getAttributes();
466  }
467 
468  return dst;
469  }
470 
472 
475  template <typename TX>
476  static inline
477  TX & xmlAssign(TX & dst, const typename TX::xml_node_t & src){
478 
479  if (&src != &dst.data){
480  dst->clear();
481  dst->getAttributes().importMap(src.getAttributes());
482  dst->setStyle(src.getStyle());
483  dst->setText(src.ctext);
484  }
485 
486  return dst;
487  }
488 
490 
495  template <typename X>
496  static inline
497  X & xmlAssignNode(X & dst, const X & src){
498 
499  if (&src != &dst){
500  //dst.clear(); // clear attributes,
501  dst.reset(); // clear attributes, style, cstring and type.
502  dst.setType(src.getType()); // important: creates links!
503  dst.getAttributes().importMap(src.getAttributes());
504  dst.setStyle(src.getStyle());
505  dst.ctext = src.ctext;
506  }
507 
508  return dst;
509  }
510 
512 
515  template <typename TX, typename V>
516  static inline
517  TX & xmlAssign(TX & tree, const V & arg){
518  tree->set(arg);
519  return tree;
520  }
521 
523 
526  template <typename TX>
527  static
528  //T & xmlAssign(T & tree, std::initializer_list<std::pair<const char *,const char *> > l){
529  TX & xmlAssign(TX & tree, std::initializer_list<std::pair<const char *,const Variable> > l){
530 
531  switch (static_cast<intval_t>(tree->getType())){
532  case STYLE:
533  for (const auto & entry: l){
534  TX & elem = tree[entry.first];
535  elem->setType(STYLE_SELECT);
536  drain::SmartMapTools::setValues(elem->getAttributes(), entry.second, ';', ':', std::string(" \t\n"));
537  }
538  break;
539  case UNDEFINED:
540  tree->setType(STYLE_SELECT);
541  // no break
542  case STYLE_SELECT:
543  default:
544  tree->set(l);
545  break;
546  }
547 
548  return tree;
549  };
550 
551 
553 
557  template <typename TX>
558  static inline
559  TX & xmlSetType(TX & tree, const typename TX::node_data_t::xml_tag_t & type){
560  tree->setType(type);
561  return tree;
562  }
563 
564 
565 
571  template <typename T>
572  static
573  T & xmlAddChild(T & tree, const std::string & key){
574  typename T::node_data_t::xml_tag_t type = xmlRetrieveDefaultType(tree.data);
575 
576  if (!key.empty()){
577  return tree[key](type);
578  }
579  else {
580  std::stringstream k("elem");
581  k.width(3);
582  k.fill('0');
583  k << tree.getChildren().size();
584  return tree[k.str()](type);
585  //return xmlGuessType(tree.data, tree[k.str()]);
586  /*
587  T & child = tree[k.str()];
588  typedef typename T::node_data_t::xml_default_elem_map_t map_t;
589  const typename map_t::const_iterator it = T::node_data_t::xml_default_elems.find(tree->getNativeType());
590  if (it != T::node_data_t::xml_default_elems.end()){
591  child->setType(it->second);
592  drain::Logger(__FILE__, __FUNCTION__).experimental<LOG_WARNING>("Default type set: ", child->getTag());
593  }
594  // NodeXML<drain::image::svg::tag_t>::xml_default_elem_map_t
595  return child;
596  */
597  }
598  }
599 
600  template <typename N>
601  static
602  typename N::xml_tag_t xmlRetrieveDefaultType(const N & parentNode){
603  typedef typename N::xml_default_elem_map_t map_t;
604  const typename map_t::const_iterator it = N::xml_default_elems.find(parentNode.getNativeType());
605  if (it != N::xml_default_elems.end()){
606  return (it->second);
607  }
608  else {
609  return static_cast<typename N::xml_tag_t>(0);
610  }
611  }
612 
613  /*
614  template <typename T>
615  static
616  T & xmlGuessType(const typename T::node_data_t & parentNode, T & child){
617  typedef typename T::node_data_t::xml_default_elem_map_t map_t;
618  const typename map_t::const_iterator it = T::node_data_t::xml_default_elems.find(parentNode.getNativeType());
619  if (it != T::node_data_t::xml_default_elems.end()){
620  child->setType(it->second);
621  drain::Logger(__FILE__, __FUNCTION__).experimental<LOG_WARNING>("Default type set: ", child->getTag());
622  }
623  return child;
624  }
625  */
626 
627 
628 };
629 
630 
631 
632 
633 
634 
635 } // drain::
636 
637 #endif /* DRAIN_XML */
638 
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:310
Logger & reject(const TT &... args)
Some input has been rejected, for example by a syntax.
Definition: Log.h:608
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition: Log.h:428
ref_t & link(const std::string &key, F &x)
Associates a map entry with a variable.
Definition: ReferenceMap.h:84
static void setValues(M &dst, const std::map< std::string, S > &srcMap)
Definition: SmartMapTools.h:176
map_t::iterator iterator
Needed?
Definition: SmartMap.h:80
std::string get(const std::string &key, const std::string &defaultValue) const
Retrieves a value, or default value if value is unset.
Definition: SmartMap.h:127
static const SprinterLayout xmlAttributeLayout
Like attributes in XML (HTML, SVG, ...) tags.
Definition: Sprinter.h:227
static std::ostream & toStream(std::ostream &ostr, const std::initializer_list< T > &x, const SprinterLayout &layout=defaultLayout)
New (experimental)
Definition: Sprinter.h:420
Definition: StringBuilder.h:58
VariableT is a final class applied through typedefs Variable, Reference and FlexibleVariable.
Definition: VariableT.h:87
void addClass(const TT &... args)
Style class.
Definition: TreeXML.h:220
void setId()
Makes ID a visible attribute.
Definition: XML.h:146
static X & xmlAssignNode(X &dst, const X &src)
Assign another tree structure to another.
Definition: XML.h:497
static TX & xmlSetType(TX &tree, const typename TX::node_data_t::xml_tag_t &type)
Definition: XML.h:559
static T & xmlAddChild(T &tree, const std::string &key)
Definition: XML.h:573
void setStyle(const std::string &key, const std::initializer_list< V > &l)
Set style of an element.
Definition: XML.h:346
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:262
static TX & xmlAssign(TX &tree, std::initializer_list< std::pair< const char *, const Variable > > l)
Tree.
Definition: XML.h:529
void setId(const TT &...args)
Concatenates arguments to an id.
Definition: XML.h:159
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
const std::string & getId() const
Returns ID of this element. Hopefully a unique ID...
Definition: XML.h:165
static TX & xmlAssign(TX &dst, const TX &src)
Assign another tree structure to another.
Definition: XML.h:458
static TX & xmlAssign(TX &dst, const typename TX::xml_node_t &src)
Assign another tree structure to another.
Definition: XML.h:477
virtual void clear()
Clear style, class and string data but keep the element type.
Definition: XML.cpp:66
static TX & xmlAssign(TX &tree, const V &arg)
Assign another tree structure to another.
Definition: XML.h:517
void reset()
Clear style, class and string data as well as the element type.
Definition: XML.h:136
void setStyle(const std::string &key, const V &value)
For element/class/id, assign ...
Definition: XML.h:362
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:72
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:177
void setAttribute(const std::string &key, const V &value)
"Final" implementation.
Definition: XML.h:269
bool hasClass(const V &cls) const
Definition: XML.h:425
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:152
Definition: DataSelector.cpp:1277
Definition: Type.h:542