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 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::SmartMapTools::setValues<map_t,true>(getAttributes(), args); // add new keys
213 // drain::SmartMapTools::setValues<map_t,false>((map_t &)*this, l); // update only
214 }
215 }
216
217
218 template <class V>
219 inline
220 void set(const std::string & key, const V & value){
221 if (type == STYLE){
222 // Modify collection directly
223 drain::Logger mout(__FILE__, __FUNCTION__);
224 mout.deprecating("Setting style as attributes of a STYLE element: ", key, ':', value);
225 setStyle(key, value);
226 }
227 else if (key == "style"){
228 drain::Logger mout(__FILE__, __FUNCTION__);
229 mout.obsolete("Setting style as attribute: \"style\"=", value);
230 }
231 else if (key == "class"){
232 // mout.warn<LOG_DEBUG>("class");
233 std::string cls;
234 drain::StringTools::import(value, cls);
235 addClass(cls);
236 }
237 else {
238 setAttribute(key, value);
239 }
240
241 }
242
243
247 virtual
248 const std::string & getTag() const {
249 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::EnumDict<T>::dict) << std::endl; // <<
250 return drain::EnumDict<T>::getDict().getKey((T)type, false);
251 }
252
256 static inline // needed?
257 const std::string & getTag(const T & type){
258 // std::cout << __FILE__ << ':' << __FUNCTION__ << ' ' << drain::TypeName<T>::str() << " dict:" << sprinter(drain::EnumDict<T>::dict) << std::endl; // <<
259 return drain::EnumDict<T>::getDict().getKey((T)type, false);
260 }
261
262
263
264 inline
265 NodeXML & operator=(const NodeXML & node){
266 return XML::xmlAssignNode(*this, node);
267 }
268
269 // Check char *
270 inline
271 NodeXML & operator=(const xml_tag_t & x){ // needed? possibly with tree(int x) ?
272 //set(x);
273 setType(x);
274 return *this;
275 }
276
277 inline
278 NodeXML & operator=(const Castable &c){
279 setText(c);
280 return *this;
281 }
282
283
284 inline
285 NodeXML & operator=(const std::string &s){
286 setText(s);
287 return *this;
288 }
289
290 inline
291 NodeXML & operator=(const char *s){
292 setText(s);
293 return *this;
294 }
295
296 inline
297 NodeXML & operator=(const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
298 set(l);
299 return *this;
300 }
301
302
304 // std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const;
308 virtual
309 std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG) const override;
310
311
312 template <class V>
313 static inline
314 std::ostream & docToStream(std::ostream & ostr, const V & tree){
315 V::node_data_t::xml_node_t::docTypeToStream(ostr);
316 V::node_data_t::xml_node_t::toStream(ostr, tree);
317 // UtilsXML::toStream(ostr, tree);
318 return ostr;
319 }
320
321
323
335 static // virtual
336 inline
337 std::ostream & docTypeToStream(std::ostream &ostr){
338 ostr << "<?xml ";
339 for (const auto & entry: xmldoc_attribs){
340 xmlAttribToStream(ostr, entry.first, entry.second);
341 }
342 ostr << "?>";
343 ostr << '\n';
344 return ostr;
345 }
346
348 typedef std::map<xml_tag_t,xml_tag_t> xml_default_elem_map_t;
349 static const xml_default_elem_map_t xml_default_elems;
350
351protected:
352
354
357 //virtual
358 //void handleType(const T & type) = 0;
359 //void handleType() = 0;
360
361
363 typedef std::list<std::pair<std::string,std::string> > xmldoc_attrib_map_t;
364 static xmldoc_attrib_map_t xmldoc_attribs;
365
366
367};
368
369template <class T>
370void NodeXML<T>::swap(NodeXML<T> & node){
371 // Swap attributes
373 // Swap classes
374 this->classList.swap(node.classList);
375}
376
377
378
379/*
380 Impossible. Cannot construct final object, for example members are not available for #link() .
381template <>
382inline
383void NodeXML<int>::handle Type(const int & type){
384 // DANGER, without cast?
385 std::cerr << __FILE__ << ':' << __FUNCTION__ << " unimplemented? " << type << '=' << std::endl;
386 std::cerr << __FILE__ << ':' << __FUNCTION__ << " dict: " << drain::sprinter(drain::EnumDict<int,XML>::dict) << std::endl;
387}
388*/
389
390template <>
391inline
392const std::string & NodeXML<int>::getTag() const {
393 return drain::EnumDict<int,XML>::dict.getKey(this->type, false);
394}
395
396typedef NodeXML<>::xml_tree_t TreeXML;
397//typedef drain::UnorderedMultiTree<NodeXML<>,false, NodeXML<>::path_t> TreeXML;
398
399// NOTE: template will not match for subclasses of NodeXML<E> because default template will match any class exactly.
400template <class E, bool EX, class P>
401struct TypeName< drain::UnorderedMultiTree<NodeXML<E>,EX,P> > {
402
403 static const std::string & str(){
404 static const std::string name = drain::StringBuilder<>("TreeXML<", TypeName<E>::str(), ">");
405 return name;
406 }
407
408};
409
410
411
412
413template <class N>
414std::ostream & NodeXML<N>::nodeToStream(std::ostream &ostr, tag_display_mode mode) const {
415
416
417 if (isCText()){
418 if (mode != CLOSING_TAG){ // or: OPENING
419 ostr << ctext; // << '(' << mode << ')'; // << " /-->\n";
420 }
421 return ostr;
422 }
423 else if (isComment()){
424 // Remember: a large subtree can be commented out
425 if (mode != CLOSING_TAG){
426 ostr << "<!--"; // << ctext; // << " /-->\n";
427 }
428 }
429 else {
430
431 if (isUndefined()){
432 drain::Logger(__FILE__, __FUNCTION__).warn("Undefined TAG type for ", getName(), " ID=", getId(), " attr=", getAttributes());
433 }
434
435 if (mode==CLOSING_TAG){
436 ostr << "</";
437 }
438 else {
439 ostr << '<';
440 }
441
442 if (getTag().empty()){
443 drain::Logger(__FILE__, __FUNCTION__).unimplemented<LOG_ERR>("defaultTag for type=", getType(), " requested by ID=", getId(), " attr=", getAttributes());
444
445 ostr << "defaultTag"; // << ' '; FIX! getDefaultTag?
446 }
447 else {
448 ostr << getTag(); // << ' ';
449 // TODO check GDAL XML
450 // if (!defaultTag.empty())
451 // attribToStream(ostr, "name", defaultTag);
452 }
453 }
454
455 if (mode != CLOSING_TAG){
456
457 if (typeIs(STYLE)){
458 // xmlAttribToStream(ostr, "data-mode", "experimental");
459 }
460 else { // if (!isCText())
461
462 specificAttributesToStream(ostr);
463
464 char sep=0;
465
466 // Iterate attributes - note: also for comment
467 for (const auto & key: getAttributes().getKeyList()){
468 std::string v = get(key, "");
469 // Skip empties (so Sprinter::toStream not applicable)
470 if (!v.empty()){
471 xmlAttribToStream(ostr, key, v);
472 sep=' ';
473 }
474 }
475
476 // Handle CSS style separately
477 if (!style.empty()){
478 if (sep)
479 ostr << sep;
480 ostr << "style=\"";
481 Sprinter::sequenceToStream(ostr, style, StyleXML::styleLineLayout);
482 ostr << '"'; // << ' ';
483 }
484
485 /*
486 if (!ctext.empty()){
487 ostr << " "; // debugging
488 }
489 */
490 }
491
492 }
493
494 // END
495 if (isComment()){
496 ostr << ' '; // prefix for free ctext
497 if (mode != OPENING_TAG){
498 // it is EMPTY_TAG or CLOSING TAG
499 ostr << "/-->"; // \n
500 }
501 // warn if has children? or comment them??
502 }
503 else if (mode==EMPTY_TAG){ // OR no ctext!
504 // close TAG
505 ostr << "/>"; // \n <- check newline - add before indent?
506 }
507 else {
508 ostr << ">";
509 }
510
511 return ostr;
512
513}
514
515
516template <class N>
517inline
518std::ostream & operator<<(std::ostream &ostr, const NodeXML<N> & node){
519 return node.nodeToStream(ostr);
520}
521
523
534DRAIN_ENUM_DICT2(int,XML);
535
536
537
538template <class E, bool EX, class P>
539std::ostream & operator<<(std::ostream &ostr, const UnorderedMultiTree<NodeXML<E>,EX,P> & tree){
540 // DOC def? TODO: preamble/prologToStream()
541 NodeXML<E>::docTypeToStream(ostr); // must be member, to support virtual?
542 NodeXML<E>::toStream(ostr, tree, "");
543 return ostr;
544}
545
546
547
548} // drain::
549
550#endif /* DRAIN_TREE_XML */
551
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 & unimplemented(const TT &... args)
Feature to be done. Special type of Logger::note().
Definition Log.h:512
Logger & deprecating(const TT &... args)
Feature will be removed. Special type of Logger::note().
Definition Log.h:522
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:337
virtual const std::string & getTag() const
Definition TreeXML.h:248
std::list< std::pair< std::string, std::string > > xmldoc_attrib_map_t
Internal function called after setType()
Definition TreeXML.h:363
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:414
static const std::string & getTag(const T &type)
Definition TreeXML.h:257
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:348
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:112
A map of references to base type scalars, arrays or std::string; changing values in either are equiva...
Definition ReferenceMap.h:69
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:589
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:623
Definition DataSelector.cpp:1277
A container for a static dictionary of enumeration values.
Definition EnumUtils.h:52
static const std::string & getKey(const std::string &s, bool lenient=true)
Convenience for object.set(...) like commands.
Definition EnumUtils.h:145
static const std::string name
Default implementation: name returned by std::type_info::name()
Definition Type.h:549