Samchon Framework for CPP  1.0.0
XML.hpp
1 #pragma once
2 #include <samchon/HashMap.hpp>
3 
4 #include <vector>
5 #include <string>
6 #include <queue>
7 #include <memory>
8 #include <sstream>
9 
10 #include <samchon/WeakString.hpp>
11 #include <samchon/library/Math.hpp>
12 
13 namespace samchon
14 {
15 namespace library
16 {
17  class XML;
18  typedef std::vector<std::shared_ptr<XML>> XMLList;
19 
69  class XML
70  : public HashMap<std::string, std::shared_ptr<XMLList>>
71  {
72  private:
74 
75  std::string tag_;
76  std::string value_;
77 
79 
80  public:
81  /* =============================================================
82  CONSTRUCTORS
83  - BASIC CONSTRUCTORS
84  - PARSERS
85  ================================================================
86  BASIC CONSTRUCTORS
87  ------------------------------------------------------------- */
93  XML() : super()
94  {
95  };
96 
104  XML(const XML &xml) : super()
105  {
106  tag_ = xml.tag_;
107  value_ = xml.value_;
108  property_map_ = xml.property_map_;
109 
110  //COPYING CHILDREN OBJECTS
111  for (auto it = xml.begin(); it != xml.end(); it++)
112  {
113  if (it->second->empty() == true)
114  continue;
115 
116  std::shared_ptr<XMLList> xmlList(new XMLList());
117  xmlList->reserve(it->second->size());
118 
119  for (size_t i = 0; i < it->second->size(); it++)
120  xmlList->emplace_back(new XML(*it->second->at(i)));
121 
122  this->set(xmlList->at(0)->tag_, xmlList);
123  }
124  };
125 
129  XML(XML &&xml) : super(move(xml))
130  {
131  tag_ = move(xml.tag_);
132  value_ = move(xml.value_);
133 
134  property_map_ = move(xml.property_map_);
135  };
136 
144  XML(WeakString wstr) : super()
145  {
146  if (wstr.find('<') == std::string::npos)
147  return;
148 
149  //WHEN COMMENT IS
150  std::string replacedStr;
151  if (wstr.find("<!--") != std::string::npos)
152  {
153  std::queue<std::pair<size_t, size_t>> indexPairQueue;
154  size_t beginX = 0, endX;
155 
156  //CONSTRUCT INDEXES
157  replacedStr.reserve(wstr.size());
158  while ((beginX = wstr.find("<!--", beginX)) != std::string::npos)
159  {
160  indexPairQueue.push({ beginX, wstr.find("-->", beginX + 1) + 3 });
161  beginX++;
162  }
163 
164  //INSERT STRINGS
165  beginX = 0;
166  while (indexPairQueue.empty() == false)
167  {
168  endX = indexPairQueue.front().first;
169  replacedStr.append(wstr.substring(beginX, endX).str());
170 
171  beginX = indexPairQueue.front().second;
172  indexPairQueue.pop();
173  }
174  replacedStr.append(wstr.substr(beginX).str());
175 
176  //RE-REFERENCE
177  wstr = replacedStr;
178  }
179 
180  //ERASE HEADERS OF XML
181  if (wstr.find("<?xml") != std::string::npos)
182  wstr = wstr.between("?>");
183 
184  parse(wstr);
185  };
186 
187  private:
188  XML(XML *parent, WeakString &wstr) : XML()
189  {
190  parse(wstr);
191  };
192 
193  /* -------------------------------------------------------------
194  PARSERS
195  ------------------------------------------------------------- */
196  void parse(WeakString &wstr)
197  {
198  parse_key(wstr);
199  parse_properties(wstr);
200 
201  if (parse_value(wstr) == true)
202  parse_children(wstr);
203  };
204 
205  void parse_key(WeakString &wstr)
206  {
207  size_t startX = wstr.find("<") + 1;
208  size_t endX =
209  calc_min_index
210  (
211  {
212  wstr.find(' ', startX),
213  wstr.find("\r\n", startX),
214  wstr.find('\n', startX),
215  wstr.find('\t', startX),
216  wstr.find('>', startX),
217  wstr.find('/', startX)
218  }
219  );
220 
221  //Determinate the KEY
222  tag_ = move( wstr.substring(startX, endX).str() );
223  };
224 
225  void parse_properties(WeakString &wstr)
226  {
227  // INLINE CLASS
228  class QuotePair
229  {
230  public:
231  enum TYPE : int
232  {
233  SINGLE = 1,
234  DOUBLE = 2
235  };
236 
237  TYPE type;
238  size_t start_index;
239  size_t end_index;
240 
241  QuotePair(TYPE type, size_t start_index, size_t end_index)
242  {
243  this->type = type;
244  this->start_index = start_index;
245  this->end_index = end_index;
246  };
247  };
248 
249  size_t i_begin = wstr.find('<' + tag_) + tag_.size() + 1;
250  size_t i_endSlash = wstr.rfind('/');
251  size_t i_endBlock = wstr.find('>', i_begin);
252 
253  size_t i_end = calc_min_index({ i_endSlash, i_endBlock });
254  if (i_end == std::string::npos || i_begin >= i_end)
255  return;
256 
257  //<comp label='ABCD' /> : " label='ABCD' "
258  WeakString &line = wstr.substring(i_begin, i_end);
259 
260  if (line.find('=') == std::string::npos)
261  return;
262 
263  std::string label, value;
264  std::vector<QuotePair*> helpers;
265  bool inQuote = false;
266  QuotePair::TYPE type;
267  size_t startPoint, equalPoint;
268  size_t i;
269 
270  for (i = 0; i < line.size(); i++)
271  {
272  //Start of quote
273  if (inQuote == false && (line[i] == '\'' || line[i] == '"'))
274  {
275  inQuote = true;
276  startPoint = i;
277 
278  if (line[i] == '\'')
279  type = QuotePair::SINGLE;
280  else if (line[i] == '"')
281  type = QuotePair::DOUBLE;
282  }
283  else if
284  (
285  inQuote == true &&
286  (
287  (type == QuotePair::SINGLE && line[i] == '\'') ||
288  (type == QuotePair::DOUBLE && line[i] == '"')
289  )
290  )
291  {
292  helpers.push_back(new QuotePair(type, startPoint, i));
293  inQuote = false;
294  }
295  }
296  for (i = 0; i < helpers.size(); i++)
297  {
298  if (i == 0)
299  {
300  equalPoint = (long long)line.find('=');
301  label = move( line.substring(0, equalPoint).trim().str() );
302  }
303  else
304  {
305  equalPoint = line.find('=', helpers[i - 1]->end_index + 1);
306  label = line.substring(helpers[i - 1]->end_index + 1, equalPoint).trim().str();
307  }
308 
309  value =
310  move
311  (
312  decodeProperty
313  (
314  line.substring
315  (
316  helpers[i]->start_index + 1,
317  helpers[i]->end_index
318  )
319  )
320  );
321 
322  //INSERT INTO PROPERTY_MAP
323  property_map_.set(label, move(value));
324  }
325  for (i = 0; i < helpers.size(); i++)
326  delete helpers[i];
327  };
328 
329  auto parse_value(WeakString &wstr) -> bool
330  {
331  size_t i_endSlash = wstr.rfind('/');
332  size_t i_endBlock = wstr.find('>');
333 
334  if (i_endSlash < i_endBlock || i_endBlock + 1 == wstr.rfind('<'))
335  {
336  //STATEMENT1: <TAG />
337  //STATEMENT2: <TAG></TAG> -> SAME WITH STATEMENT1: <TAG />
338  value_.clear();
339  return false;
340  }
341 
342  size_t startX = i_endBlock + 1;
343  size_t endX = wstr.rfind('<');
344  wstr = wstr.substring(startX, endX); //REDEFINE WEAK_STRING -> IN TO THE TAG
345 
346  if (wstr.find('<') == std::string::npos)
347  value_ = wstr.trim();
348  else
349  value_.clear();
350 
351  return true;
352  };
353 
354  void parse_children(WeakString &wstr)
355  {
356  if (wstr.find('<') == std::string::npos)
357  return;
358 
359  size_t startX = wstr.find('<');
360  size_t endX = wstr.rfind('>') + 1;
361  wstr = wstr.substring(startX, endX);
362 
363  /*map<std::string, queue<XML *>> xmlQueueMap;
364  queue<XML*> *xmlQueue;
365  XML *xml;*/
366 
367  int blockStartCount = 0;
368  int blockEndCount = 0;
369  size_t start = 0;
370  size_t end;
371  size_t i;
372 
373  //FIND BLOCKS, CREATES XML AND PUT IN TEMPORARY CONTAINER
374  for (i = 0; i < wstr.size(); i++)
375  {
376  if (wstr[i] == '<' && wstr.substr(i, 2) != "</")
377  blockStartCount++;
378  else if (wstr.substr(i, 2) == "/>" || wstr.substr(i, 2) == "</")
379  blockEndCount++;
380 
381  if (blockStartCount >= 1 && blockStartCount == blockEndCount)
382  {
383  //NO PROBLEM TO AVOID COMMENT
384  end = wstr.find('>', i);
385 
386  /*xml = new XML(this, wstr.substring(start, end + 1));
387  xmlQueueMap[xml->tag].push(xml);*/
388 
389  std::shared_ptr<XML> xml(new XML(this, wstr.substring(start, end + 1)));
390  push_back(xml);
391 
392  i = end; //WHY NOT END+1?
393  start = end + 1;
394  blockStartCount = 0;
395  blockEndCount = 0;
396  }
397  }
398 
399  //RESERVE
400  /*for (auto it = xmlQueueMap.begin(); it != xmlQueueMap.end(); it++)
401  {
402  std::string tag = move(it->first); //GET KEY
403  shared_ptr<XMLList> xmlList(new XMLList());
404 
405  xmlQueue = &(it->second);
406  xmlList->reserve(xmlQueue->size()); //RESERVE
407 
408  //MOVE QUEUE TO XML_LIST
409  while (xmlQueue->empty() == false)
410  {
411  xml = xmlQueue->front();
412  xmlList->push_back(shared_ptr<XML>(xml));
413 
414  xmlQueue->pop();
415  }
416  //INSERT IN MAP BY KEY
417  insert({ tag, xmlList });
418  }*/
419 
420  if (size() > 0)
421  value_.clear();
422  };
423 
424  public:
425  /* =============================================================
426  ACCESSORS
427  - GETTERS
428  - VALUE TEMPLATES
429  - PROPERTY TEMPLATES
430  - SETTERS
431  - VALUE TEMPLATES
432  - PROPERTY TEMPLATES
433  - ELEMENTS I/O
434  ================================================================
435  GETTERS
436  ------------------------------------------------------------- */
447  auto getTag() const -> std::string
448  {
449  return tag_;
450  };
451 
461  auto hasProperty(const std::string &key) const -> bool
462  {
463  return property_map_.has(key);
464  };
465 
477  auto getPropertyMap() const -> const HashMap<std::string, std::string>&
478  {
479  return property_map_;
480  };
481 
482  /* -------------------------------------------------------------
483  GETTERS - VALUE TEMPLATES
484  ------------------------------------------------------------- */
495  template<class T = std::string> auto getValue() const -> T
496  {
497  double val = std::stod(value_);
498 
499  return (T)val;
500  };
501 
502  template<> auto getValue() const -> bool
503  {
504  return value_ == "true";
505  };
506 
507  template<> auto getValue() const -> std::string
508  {
509  return value_;
510  };
511  template<> auto getValue() const -> WeakString
512  {
513  return value_;
514  };
515 
516  /* -------------------------------------------------------------
517  GETTERS - PROPERTY TEMPLATES
518  ------------------------------------------------------------- */
537  template<class T = std::string> auto getProperty(const std::string &key) const -> T
538  {
539  double val = std::stod(property_map_.get(key));
540 
541  return (T)val;
542  };
543 
544  template<> auto getProperty(const std::string &key) const -> bool
545  {
546  const std::string &val = property_map_.get(key);
547 
548  return val == "true" || val == "1";
549  };
550 
551  template<> auto getProperty(const std::string &key) const -> std::string
552  {
553  return property_map_.get(key);
554  };
555  template<> auto getProperty(const std::string &key) const -> WeakString
556  {
557  return property_map_.get(key);
558  };
559 
580  auto findProperty(const std::string &key) ->HashMap<std::string, std::string>::iterator
581  {
582  return property_map_.find(key);
583  };
584 
585  auto findProperty(const std::string &key) const -> HashMap<std::string, std::string>::const_iterator
586  {
587  return property_map_.find(key);
588  };
589 
590  template <typename T = std::string>
591  auto fetchProperty(const std::string &key, const T &def = T()) const -> T
592  {
593  if (hasProperty(key))
594  return getProperty<T>(key);
595  else
596  return def;
597  };
598 
599  /* -----------------------------------------------------------
600  SETTERS
601  ----------------------------------------------------------- */
617  void setTag(const std::string &val)
618  {
619  tag_ = val;
620  };
621 
622  /* -------------------------------------------------------------
623  SETTERS - VALUE TEMPLATES
624  ------------------------------------------------------------- */
634  template <typename T>
635  void setValue(const T &val)
636  {
637  value_ = std::to_string(val);
638  };
639 
640  template<> void setValue(const bool &flag)
641  {
642  this->value_ = flag ? "true" : "false";
643  };
644 
645  template<> void setValue(const std::string &val)
646  {
647  this->value_ = val;
648  };
649  template<> void setValue(const WeakString &val)
650  {
651  this->value_ = val.str();
652  };
653  void setValue(const char *ptr)
654  {
655  this->value_ = ptr;
656  };
657 
658  /* -------------------------------------------------------------
659  SETTERS - PROPERTY TEMPLATES
660  ------------------------------------------------------------- */
681  template<typename T>
682  void setProperty(const std::string &key, const T &val)
683  {
684  property_map_.set(key, std::to_string(val));
685  };
686 
687  template<> void setProperty(const std::string &key, const bool &flag)
688  {
689  property_map_.set(key, flag ? "true" : "false");
690  };
691 
692  template<> void setProperty(const std::string &key, const std::string &val)
693  {
694  property_map_.set(key, val);
695  };
696  template<> void setProperty(const std::string &key, const WeakString &val)
697  {
698  property_map_.set(key, val.str());
699  };
700  void setProperty(const std::string &key, const char *ptr)
701  {
702  property_map_.set(key, ptr);
703  };
704 
705  /* -----------------------------------------------------------
706  ELEMENTS I/O
707  ----------------------------------------------------------- */
714  {
715  if (wstr.empty() == true)
716  return;
717 
718  std::shared_ptr<XML> xml(new XML(this, wstr));
719  auto it = find(xml->tag_);
720 
721  //if not exists
722  if (it == end())
723  {
724  set(xml->tag_, std::make_shared<XMLList>());
725  it = find(xml->tag_);
726  }
727 
728  //insert
729  it->second->push_back(xml);
730  };
731 
737  void push_back(const std::shared_ptr<XML> xml)
738  {
739  std::string &tag = xml->tag_;
740 
741  if (this->has(tag) == false)
742  this->set(tag, std::make_shared<XMLList>());
743 
744  this->get(tag)->push_back(xml);
745  };
746 
747  template <typename T>
748  void insertValue(const std::string &tag, const T &val)
749  {
750  std::shared_ptr<XML> xml(new XML());
751  xml->setTag(tag);
752  xml->setValue(val);
753 
754  push_back(xml);
755  };
756 
781  void insertAllProperties(const std::shared_ptr<XML> xml)
782  {
783  for (auto it = xml->property_map_.begin(); it != xml->property_map_.end(); it++)
784  property_map_[it->first] = it->second;
785  };
786 
803  void eraseProperty(const std::string &key)
804  {
805  property_map_.erase(key);
806  };
807 
820  {
821  property_map_.clear();
822  };
823 
824  private:
825  /* -----------------------------------------------------------
826  FILTERS
827  ----------------------------------------------------------- */
828  auto calc_min_index(const std::vector<size_t> &vec) const -> size_t
829  {
830  size_t val = std::string::npos;
831  for (size_t i = 0; i < vec.size(); i++)
832  if (vec[i] != std::string::npos && vec[i] < val)
833  val = vec[i];
834 
835  return val;
836  };
837 
838  auto encode_value(const WeakString &wstr) const -> std::string
839  {
840  static std::vector<std::pair<std::string, std::string>> pairArray =
841  {
842  { "&", "&amp;" },
843  { "<", "&lt;" },
844  { ">", "&gt;" }
845  };
846 
847  return wstr.replaceAll(pairArray);
848  };
849 
850  auto decode_value(const WeakString &wstr) const -> std::string
851  {
852  static std::vector<std::pair<std::string, std::string>> pairArray =
853  {
854  { "&amp;", "&" },
855  { "&lt;", "<" },
856  { "&gt;", ">" }
857  };
858 
859  return wstr.replaceAll(pairArray);
860  };
861 
862  auto encode_property(const WeakString &wstr) const -> std::string
863  {
864  static std::vector<std::pair<std::string, std::string>> pairArray =
865  {
866  { "&", "&amp;" },
867  { "<", "&lt;" },
868  { ">", "&gt;" },
869  { "\"", "&quot;" },
870  { "'", "&apos;" },
871  { "\t", "&#x9;" }, //9
872  { "\n", "&#xA;" }, //10
873  { "\r", "&#xD;" } //13
874  };
875 
876  return wstr.trim().replaceAll(pairArray);
877  };
878 
879  auto decodeProperty(const WeakString &wstr) const -> std::string
880  {
881  static std::vector<std::pair<std::string, std::string>> pairArray =
882  {
883  { "&amp;", "&" },
884  { "&lt;", "<" },
885  { "&gt;", ">" },
886  { "&quot;", "\"" },
887  { "&apos;", "'" },
888  { "&#x9;", "\t" }, //9
889  { "&#xA;", "\n" }, //10
890  { "&#xD;", "\r" } //13
891  };
892 
893  return wstr.replaceAll(pairArray);
894  };
895 
896  /* -----------------------------------------------------------
897  EXPORTERS
898  ----------------------------------------------------------- */
899  public:
908  auto toString(size_t level = 0) const -> std::string
909  {
910  // KEY
911  std::string str = std::string(level, '\t') + "<" + tag_;
912 
913  // PROPERTIES
914  for (auto it = property_map_.begin(); it != property_map_.end(); it++)
915  str += " " + it->first + "=\"" + encode_property(it->second) + "\"";
916 
917  if (this->empty() == true)
918  {
919  // VALUE
920  if (value_.empty() == true)
921  str += " />";
922  else
923  str += ">" + encode_value(value_) + "</" + tag_ + ">";
924  }
925  else
926  {
927  // CHILDREN
928  str += ">\n";
929 
930  for (auto it = begin(); it != end(); it++)
931  for (size_t i = 0; i < it->second->size(); i++)
932  str += it->second->at(i)->toString(level + 1);
933 
934  str += std::string(level, '\t') + "</" + tag_ + ">";
935  }
936 
937  return str + "\n";
938  };
939  };
940 };
941 };
auto str() const -> std::string
Get the string content.
Definition: WeakString.hpp:926
void clearProperties()
Definition: XML.hpp:819
auto has(const Key &key) const -> bool
Whether have the item or not.
Definition: HashMap.hpp:125
auto empty() const -> bool
Tests wheter string is emtpy.
Definition: WeakString.hpp:231
auto toString(size_t level=0) const -> std::string
Definition: XML.hpp:908
auto replaceAll(const WeakString &before, const WeakString &after) const -> std::string
Returns a string specified word is replaced.
Definition: WeakString.hpp:763
void eraseProperty(const std::string &key)
Definition: XML.hpp:803
auto findProperty(const std::string &key) -> HashMap< std::string, std::string >::iterator
Definition: XML.hpp:580
void insertAllProperties(const std::shared_ptr< XML > xml)
Definition: XML.hpp:781
XML(WeakString wstr)
Definition: XML.hpp:144
auto get(const Key &key) -> T &
Get element.
Definition: HashMap.hpp:144
XML()
Default Constructor.
Definition: XML.hpp:93
auto between(const WeakString &start={}, const WeakString &end={}) const -> WeakString
Generates a substring.
Definition: WeakString.hpp:475
auto getTag() const -> std::string
Get tag.
Definition: XML.hpp:447
auto substring(size_t startIndex, size_t endIndex=SIZE_MAX) const -> WeakString
Generates a substring.
Definition: WeakString.hpp:443
XML(XML &&xml)
Move Constructor.
Definition: XML.hpp:129
auto find(const WeakString &delim, size_t startIndex=NULL) const -> size_t
Finds first occurence in string.
Definition: WeakString.hpp:273
void setProperty(const std::string &key, const T &val)
Definition: XML.hpp:682
auto getValue() const -> T
Get value.
Definition: XML.hpp:495
void push_back(const std::shared_ptr< XML > xml)
Add children xml.
Definition: XML.hpp:737
void setTag(const std::string &val)
Definition: XML.hpp:617
auto getPropertyMap() const -> const HashMap< std::string, std::string > &
Definition: XML.hpp:477
auto substr(size_t startIndex, size_t size=SIZE_MAX) const -> WeakString
Generates a substring.
Definition: WeakString.hpp:419
void push_back(WeakString wstr)
Add children xml objects by string representing them.
Definition: XML.hpp:713
auto getProperty(const std::string &key) const -> T
Get property.
Definition: XML.hpp:537
XML(const XML &xml)
Copy Constructor.
Definition: XML.hpp:104
void set(const Key &key, const T &val)
Set element.
Definition: HashMap.hpp:165
auto hasProperty(const std::string &key) const -> bool
Definition: XML.hpp:461
void setValue(const T &val)
Definition: XML.hpp:635
auto size() const -> size_t
Returns size of the characters which are being referenced.
Definition: WeakString.hpp:217
auto rfind(const WeakString &delim, size_t endIndex=SIZE_MAX) const -> size_t
Finds last occurence in string.
Definition: WeakString.hpp:297
Customized std::unordered_map.
Definition: HashMap.hpp:103
A string class only references characeters, reference only.
Definition: WeakString.hpp:35