Samchon Framework for CPP  1.0.0
XML.cpp
1 #include <samchon/library/XML.hpp>
2 
3 #include <list>
4 #include <queue>
5 
6 #include <samchon/library/Math.hpp>
7 
8 using namespace std;
9 using namespace samchon;
10 using namespace samchon::library;
11 
12 class QuotePair
13 {
14 public:
15  enum TYPE : int
16  {
17  SINGLE = 1,
18  DOUBLE = 2
19  };
20 
21  TYPE type;
22  size_t startIndex;
23  size_t endIndex;
24 
25  QuotePair(TYPE type, size_t startIndex, size_t endIndex)
26  {
27  this->type = type;
28  this->startIndex = startIndex;
29  this->endIndex = endIndex;
30  };
31 };
32 
33 /* -------------------------------------------------------------------
34  CONSTRUCTORS
35 ------------------------------------------------------------------- */
36 XML::XML()
37  : super()
38 {
39 // parent = nullptr;
40 // level = 0;
41 }
42 XML::XML(const XML &xml)
43  : super()
44 {
45  tag = xml.tag;
46  value = xml.value;
47 
49 
50  //COPYING CHILDREN OBJECTS
51  for (auto it = xml.begin(); it != xml.end(); it++)
52  {
53  if (it->second->empty() == true)
54  continue;
55 
56  shared_ptr<XMLList> xmlList(new XMLList());
57  xmlList->reserve(it->second->size());
58 
59  for (size_t i = 0; i < it->second->size(); it++)
60  xmlList->emplace_back(new XML(*it->second->at(i)));
61 
62  set(xmlList->at(0)->tag, xmlList);
63  }
64 }
65 XML::XML(XML &&xml)
66  : super(move(xml))
67 {
68  tag = move(xml.tag);
69  value = move(xml.value);
70 
71  propertyMap = move(xml.propertyMap);
72 }
73 
75  : XML()
76 {
77  if (wStr.find('<') == std::string::npos)
78  return;
79 
80  //WHEN COMMENT IS
81  std::string replacedStr;
82  if (wStr.find("<!--") != std::string::npos)
83  {
84  queue<pair<size_t, size_t>> indexPairQueue;
85  size_t beginX = 0, endX;
86 
87  //CONSTRUCT INDEXES
88  replacedStr.reserve(wStr.size());
89  while ((beginX = wStr.find("<!--", beginX)) != std::string::npos)
90  {
91  indexPairQueue.push({ beginX, wStr.find("-->", beginX + 1) + 3 });
92  beginX++;
93  }
94 
95  //INSERT STRINGS
96  beginX = 0;
97  while (indexPairQueue.empty() == false)
98  {
99  endX = indexPairQueue.front().first;
100  replacedStr.append(wStr.substring(beginX, endX).str());
101 
102  beginX = indexPairQueue.front().second;
103  indexPairQueue.pop();
104  }
105  replacedStr.append(wStr.substr(beginX).str());
106 
107  //RE-REFERENCE
108  wStr = replacedStr;
109  }
110 
111  //ERASE HEADERS OF XML
112  if (wStr.find("<?xml") != std::string::npos)
113  wStr = wStr.between("?>");
114 
115  construct(wStr);
116 }
117 XML::XML(XML *parent, WeakString &str)
118  : XML()
119 {
120 // this->parent = parent;
121 // this->level = parent->level + 1;
122 
123  construct(str);
124 }
125 
126 void XML::construct(WeakString &wStr)
127 {
128  constructKey(wStr);
129  constructProperty(wStr);
130  if (constructValue(wStr) == true)
131  constructChildren(wStr);
132 }
133 void XML::constructKey(WeakString &wStr)
134 {
135  size_t startX = wStr.find("<") + 1;
136  size_t endX =
137  calcMinIndex
138  (
139  {
140  wStr.find(' ', startX),
141  wStr.find("\r\n", startX),
142  wStr.find('\n', startX),
143  wStr.find('\t', startX),
144  wStr.find('>', startX),
145  wStr.find('/', startX)
146  }
147  );
148 
149  //Determinate the KEY
150  tag = move( wStr.substring(startX, endX).str() );
151 }
152 void XML::constructProperty(WeakString &wStr)
153 {
154  size_t i_begin = wStr.find('<' + tag) + tag.size() + 1;
155  size_t i_endSlash = wStr.rfind('/');
156  size_t i_endBlock = wStr.find('>', i_begin);
157 
158  size_t i_end = calcMinIndex({ i_endSlash, i_endBlock });
159  if (i_end == std::string::npos || i_begin >= i_end)
160  return;
161 
162  //<comp label='ABCD' /> : " label='ABCD' "
163  WeakString &line = wStr.substring(i_begin, i_end);
164 
165  if (line.find('=') == std::string::npos)
166  return;
167 
168  std::string label, value;
169  vector<QuotePair*> helpers;
170  bool inQuote = false;
171  QuotePair::TYPE type;
172  size_t startPoint, equalPoint;
173  size_t i;
174 
175  for (i = 0; i < line.size(); i++)
176  {
177  //Start of quote
178  if (inQuote == false && (line[i] == '\'' || line[i] == '"'))
179  {
180  inQuote = true;
181  startPoint = i;
182 
183  if (line[i] == '\'')
184  type = QuotePair::SINGLE;
185  else if (line[i] == '"')
186  type = QuotePair::DOUBLE;
187  }
188  else if
189  (
190  inQuote == true &&
191  (
192  (type == QuotePair::SINGLE && line[i] == '\'') ||
193  (type == QuotePair::DOUBLE && line[i] == '"')
194  )
195  )
196  {
197  helpers.push_back(new QuotePair(type, startPoint, i));
198  inQuote = false;
199  }
200  }
201  for (i = 0; i < helpers.size(); i++)
202  {
203  if (i == 0)
204  {
205  equalPoint = (long long)line.find('=');
206  label = move( line.substring(0, equalPoint).trim().str() );
207  }
208  else
209  {
210  equalPoint = line.find('=', helpers[i - 1]->endIndex + 1);
211  label = line.substring(helpers[i - 1]->endIndex + 1, equalPoint).trim().str();
212  }
213 
214  value =
215  move
216  (
217  decodeProperty
218  (
219  line.substring
220  (
221  helpers[i]->startIndex + 1,
222  helpers[i]->endIndex
223  )
224  )
225  );
226 
227  //INSERT INTO PROPERTY_MAP
228  propertyMap.set(label, move(value));
229  }
230  for (i = 0; i < helpers.size(); i++)
231  delete helpers[i];
232 }
233 auto XML::constructValue(WeakString &wStr) -> bool
234 {
235  size_t i_endSlash = wStr.rfind('/');
236  size_t i_endBlock = wStr.find('>');
237 
238  if (i_endSlash < i_endBlock || i_endBlock + 1 == wStr.rfind('<'))
239  {
240  //STATEMENT1: <TAG />
241  //STATEMENT2: <TAG></TAG> -> SAME WITH STATEMENT1: <TAG />
242  value.clear();
243  return false;
244  }
245 
246  size_t startX = i_endBlock + 1;
247  size_t endX = wStr.rfind('<');
248  wStr = wStr.substring(startX, endX); //REDEFINE WEAK_STRING -> IN TO THE TAG
249 
250  if (wStr.find('<') == string::npos)
251  value = move( wStr.trim().str() );
252  else
253  value.clear();
254 
255  return true;
256 }
257 void XML::constructChildren(WeakString &wStr)
258 {
259  if (wStr.find('<') == std::string::npos)
260  return;
261 
262  size_t startX = wStr.find('<');
263  size_t endX = wStr.rfind('>') + 1;
264  wStr = wStr.substring(startX, endX);
265 
266  /*map<std::string, queue<XML *>> xmlQueueMap;
267  queue<XML*> *xmlQueue;
268  XML *xml;*/
269 
270  int blockStartCount = 0;
271  int blockEndCount = 0;
272  size_t start = 0;
273  size_t end;
274  size_t i;
275 
276  //FIND BLOCKS, CREATES XML AND PUT IN TEMPORARY CONTAINER
277  for (i = 0; i < wStr.size(); i++)
278  {
279  if (wStr[i] == '<' && wStr.substr(i, 2) != "</")
280  blockStartCount++;
281  else if (wStr.substr(i, 2) == "/>" || wStr.substr(i, 2) == "</")
282  blockEndCount++;
283 
284  if (blockStartCount >= 1 && blockStartCount == blockEndCount)
285  {
286  //NO PROBLEM TO AVOID COMMENT
287  end = wStr.find('>', i);
288 
289  /*xml = new XML(this, wStr.substring(start, end + 1));
290  xmlQueueMap[xml->tag].push(xml);*/
291 
292  shared_ptr<XML> xml(new XML(this, wStr.substring(start, end + 1)));
293  push_back(xml);
294 
295  i = end; //WHY NOT END+1?
296  start = end + 1;
297  blockStartCount = 0;
298  blockEndCount = 0;
299  }
300  }
301 
302  //RESERVE
303  /*for (auto it = xmlQueueMap.begin(); it != xmlQueueMap.end(); it++)
304  {
305  std::string tag = move(it->first); //GET KEY
306  shared_ptr<XMLList> xmlList(new XMLList());
307 
308  xmlQueue = &(it->second);
309  xmlList->reserve(xmlQueue->size()); //RESERVE
310 
311  //MOVE QUEUE TO XML_LIST
312  while (xmlQueue->empty() == false)
313  {
314  xml = xmlQueue->front();
315  xmlList->push_back(shared_ptr<XML>(xml));
316 
317  xmlQueue->pop();
318  }
319  //INSERT IN MAP BY KEY
320  insert({ tag, xmlList });
321  }*/
322 
323  if (size() > 0)
324  value.clear();
325 }
326 
327 /* -------------------------------------------------------------------
328  GETTERS
329 ------------------------------------------------------------------- */
330 auto XML::getTag() const -> std::string
331 {
332  return this->tag;
333 }
334 
335 /*template<> auto XML::getValue() const -> int
336 {
337  return stoi(value);
338 }
339 template<> auto XML::getValue() const -> long
340 {
341  return stol(value);
342 }
343 template<> auto XML::getValue() const -> long long
344 {
345  return stoll(value);
346 }
347 template<> auto XML::getValue() const -> float
348 {
349  return stof(value);
350 }
351 template<> auto XML::getValue() const -> double
352 {
353  return stod(value);
354 }
355 template<> auto XML::getValue() const -> unsigned int
356 {
357 #ifdef _WIN64
358  return (unsigned int)stoul(value);
359 #else
360  return (unsigned int)stoull(value);
361 #endif
362 }
363 template<> auto XML::getValue() const -> unsigned long
364 {
365  return stoul(value);
366 }
367 template<> auto XML::getValue() const -> unsigned long long
368 {
369  return stoull(value);
370 }
371 template<> auto XML::getValue() const -> long double
372 {
373  return stold(value);
374 }
375 
376 template<> auto XML::getValue() const -> std::string
377 {
378  return value;
379 }*/
380 
381 /* -------------------------------------------------------------------
382  SETTERS
383 ------------------------------------------------------------------- */
384 void XML::setTag(const std::string &tag)
385 {
386  this->tag = tag;
387 }
388 
389 /*template<> void XML::setValue(const int &value)
390 {
391  this->value = std::to_string(value);
392 }
393 template<> void XML::setValue(const long &value)
394 {
395  this->value = std::to_string(value);
396 }
397 template<> void XML::setValue(const long long &value)
398 {
399  this->value = std::to_string(value);
400 }
401 template<> void XML::setValue(const float &value)
402 {
403  this->value = std::to_string(value);
404 }
405 template<> void XML::setValue(const double &value)
406 {
407  this->value = std::to_string(value);
408 }
409 template<> void XML::setValue(const unsigned int &value)
410 {
411  this->value = std::to_string(value);
412 }
413 template<> void XML::setValue(const unsigned long &value)
414 {
415  this->value = std::to_string(value);
416 }
417 template<> void XML::setValue(const unsigned long long &value)
418 {
419  this->value = std::to_string(value);
420 }
421 template<> void XML::setValue(const long double &value)
422 {
423  this->value = std::to_string(value);
424 }
425 
426 template<> void XML::setValue(const std::string &value)
427 {
428  this->value = value;
429 }
430 template<> void XML::setValue(const shared_ptr<XML> &xml)
431 {
432  clear();
433  push_back(xml);
434 }*/
435 
436 /* -------------------------------------------------------------------
437  METHODS OF MAP
438 ------------------------------------------------------------------- */
439 void XML::push_back(const WeakString &str)
440 {
441  if (str.empty() == true)
442  return;
443 
444  shared_ptr<XML> xml(new XML(this, (WeakString&)str));
445  auto it = find(xml->tag);
446 
447  //if not exists
448  if (it == end())
449  {
450  set(xml->tag, make_shared<XMLList>());
451  it = find(xml->tag);
452  }
453 
454  //insert
455  it->second->push_back(xml);
456 }
457 void XML::push_back(const shared_ptr<XML> xml)
458 {
459  std::string &tag = xml->tag;
460  if (this->has(tag) == false)
461  set(tag, make_shared<XMLList>());
462 
463  this->get(tag)->push_back(xml);
464 }
465 
466 /* -------------------------------------------------------------------
467  METHODS OF PROPERTIES
468 ------------------------------------------------------------------- */
469 void XML::addAllProperty(const shared_ptr<XML> xml)
470 {
471 // propertyMap.insert( propertyMap.end(),
472 // xml->propertyMap.begin(), xml->propertyMap.end() );
473  for (auto it = xml->propertyMap.begin(); it != xml->propertyMap.end(); it++)
474  propertyMap[it->first] = it->second;
475 }
476 void XML::eraseProperty(const std::string &tag)
477 {
478  propertyMap.erase(tag);
479 }
481 {
482  propertyMap.clear();
483 }
484 
485 auto XML::getPropertyMap() const -> const HashMap<std::string, std::string>&
486 {
487  return propertyMap;
488 }
489 
490 //GETTERS
491 auto XML::hasProperty(const std::string &tag) const -> bool
492 {
493  return propertyMap.has(tag);
494 }
495 
496 /*template<> auto XML::getProperty(const std::string &tag) const -> int
497 {
498  return stoi( propertyMap.get(tag) );
499 }
500 template<> auto XML::getProperty(const std::string &tag) const -> long
501 {
502  return stol( propertyMap.get(tag) );
503 }
504 template<> auto XML::getProperty(const std::string &tag) const -> long long
505 {
506  return stoll( propertyMap.get(tag) );
507 }
508 template<> auto XML::getProperty(const std::string &tag) const -> float
509 {
510  return stof( propertyMap.get(tag) );
511 }
512 template<> auto XML::getProperty(const std::string &tag) const -> double
513 {
514  return stod( propertyMap.get(tag) );
515 }
516 template<> auto XML::getProperty(const std::string &tag) const -> unsigned int
517 {
518  return (unsigned int)stoull( propertyMap.get(tag) );
519 }
520 template<> auto XML::getProperty(const std::string &tag) const -> unsigned long
521 {
522  return stoul( propertyMap.get(tag) );
523 }
524 template<> auto XML::getProperty(const std::string &tag) const -> unsigned long long
525 {
526  return stoll( propertyMap.get(tag) );
527 }
528 template<> auto XML::getProperty(const std::string &tag) const -> long double
529 {
530  return stold( propertyMap.get(tag) );
531 }
532 template<> auto XML::getProperty(const std::string &tag) const -> std::string
533 {
534  return propertyMap.get(tag);
535 }*/
536 
537 //SETTERS
538 /*template<> void XML::setProperty(const std::string &tag, const int &val)
539 {
540  propertyMap.set(tag, std::to_string(val));
541 }
542 template<> void XML::setProperty(const std::string &tag, const long &val)
543 {
544  propertyMap.set(tag, std::to_string(val));
545 }
546 template<> void XML::setProperty(const std::string &tag, const long long &val)
547 {
548  propertyMap.set(tag, std::to_string(val));
549 }
550 template<> void XML::setProperty(const std::string &tag, const float &val)
551 {
552  propertyMap.set(tag, std::to_string(val));
553 }
554 template<> void XML::setProperty(const std::string &tag, const double &val)
555 {
556  propertyMap.set(tag, std::to_string(val));
557 }
558 template<> void XML::setProperty(const std::string &tag, const unsigned int &val)
559 {
560  propertyMap.set(tag, std::to_string(val));
561 }
562 template<> void XML::setProperty(const std::string &tag, const unsigned long &val)
563 {
564  propertyMap.set(tag, std::to_string(val));
565 }
566 template<> void XML::setProperty(const std::string &tag, const unsigned long long &val)
567 {
568  propertyMap.set(tag, std::to_string(val));
569 }
570 template<> void XML::setProperty(const std::string &tag, const long double &val)
571 {
572  propertyMap.set(tag, std::to_string(val));
573 }
574 template<> void XML::setProperty(const std::string &tag, const std::string &val)
575 {
576  propertyMap.set(tag, val);
577 }*/
578 
579 /* -------------------------------------------------------------------
580  UTILITY
581 ------------------------------------------------------------------- */
582 auto XML::calcMinIndex(const std::vector<size_t> &vec) const -> size_t
583 {
584  size_t val = std::string::npos;
585  for (size_t i = 0; i < vec.size(); i++)
586  if (vec[i] != std::string::npos && vec[i] < val)
587  val = vec[i];
588 
589  return val;
590 }
591 
592 auto XML::encodeProperty(const WeakString &str) const -> std::string
593 {
594  static vector<pair<std::string, std::string>> pairArray =
595  {
596  { "&", "&amp;" },
597  { "<", "&lt;" },
598  { ">", "&gt;" },
599  { "\"", "&quot;" },
600  { "'", "&apos;" },
601  { "\t", "&#x9;" }, //9
602  { "\n", "&#xA;" }, //10
603  { "\r", "&#xD;" } //13
604  };
605 
606  return str.replaceAll(pairArray);
607 }
608 auto XML::decodeProperty(const WeakString &str) const -> std::string
609 {
610  static vector<pair<std::string, std::string>> pairArray =
611  {
612  { "&amp;", "&" },
613  { "&lt;", "<" },
614  { "&gt;", ">" },
615  { "&quot;", "\"" },
616  { "&apos;", "'" },
617  { "&#x9;", "\t" }, //9
618  { "&#xA;", "\n" }, //10
619  { "&#xD;", "\r" } //13
620  };
621 
622  return str.replaceAll(pairArray);
623 }
624 auto XML::encodeValue(const WeakString &str) const -> std::string
625 {
626  static vector<pair<std::string, std::string>> pairArray =
627  {
628  { "&", "&amp;" },
629  { "<", "&lt;" },
630  { ">", "&gt;" }
631  };
632 
633  return str.trim().replaceAll(pairArray);
634 }
635 auto XML::decodeValue(const WeakString &str) const -> std::string
636 {
637  static vector<pair<std::string, std::string>> pairArray =
638  {
639  { "&amp;", "&" },
640  { "&lt;", "<" },
641  { "&gt;", ">" }
642  };
643 
644  return str.replaceAll(pairArray);
645 }
646 
647 auto XML::toString(size_t level) const -> string
648 {
649  // KEY
650  string str = string(level, '\t') + "<" + tag;
651 
652  // PROPERTIES
653  for (auto it = propertyMap.begin(); it != propertyMap.end(); it++)
654  str += " " + it->first + "=\"" + encodeProperty(it->second) + "\"";
655 
656  if (this->empty() == true)
657  {
658  // VALUE
659  if (value.empty() == true)
660  str += " />";
661  else
662  str += ">" + encodeValue(value) + "</" + tag + ">";
663  }
664  else
665  {
666  // CHILDREN
667  str += ">\n";
668 
669  for (auto it = begin(); it != end(); it++)
670  for (size_t i = 0; i < it->second->size(); i++)
671  str += it->second->at(i)->toString(level + 1);
672 
673  str += string(level, '\t') + "</" + tag + ">";
674  }
675 
676  return str + "\n";
677 }
std::vector< std::shared_ptr< XML > > XMLList
A list of XML, tags are same.
Definition: XMLList.hpp:19
std::string value
Value of the XML.
Definition: XML.hpp:94
XML()
Default Constructor.
Definition: XML.cpp:36
auto has(const std::string &key) const -> bool
Whether have the item or not.
Definition: HashMap.hpp:127
auto pop(const Key &key) -> T
Pop item.
Definition: HashMap.hpp:190
auto substr(size_t startIndex, size_t endIndex=SIZE_MAX) const -> WeakString
Generates a substring.
Definition: WeakString.cpp:174
auto empty() const -> bool
Tests wheter string is emtpy.
Definition: WeakString.cpp:74
auto size() const -> size_t
Returns size of the characters which are being referenced.
Definition: WeakString.cpp:69
Definition: RWMutex.hpp:4
Package of libraries.
Definition: library.hpp:84
void eraseProperty(const std::string &)
Erase a property by its key.
Definition: XML.cpp:476
std::string tag
Tag name.
Definition: XML.hpp:85
void push_back(const WeakString &)
Add children xml objects by string representing them.
Definition: XML.cpp:439
auto getPropertyMap() const -> const HashMap< std::string, std::string > &
Get propertyMap.
Definition: XML.cpp:485
auto find(const WeakString &delim, size_t startIndex=NULL) const -> size_t
Finds first occurence in string.
Definition: WeakString.cpp:91
void setTag(const std::string &)
Set tag (identifier) of the XML.
Definition: XML.cpp:384
void clearProperties()
Remove all properties in the XML.
Definition: XML.cpp:480
auto rfind(const WeakString &delim, size_t endIndex=SIZE_MAX) const -> size_t
Finds last occurence in string.
Definition: WeakString.cpp:103
HashMap< std::string, std::string > propertyMap
Properties belongs to the XML.
Definition: XML.hpp:106
auto toString(size_t level=0) const -> std::string
Get the string content.
Definition: XML.cpp:647
auto trim(const std::vector< std::string > &delims) const -> WeakString
Removes all designated characters from the beginning and end of the specified string.
Definition: WeakString.cpp:374
auto substring(size_t startIndex, size_t size=SIZE_MAX) const -> WeakString
Generates a substring.
Definition: WeakString.cpp:181
auto replaceAll(const WeakString &before, const WeakString &after) const -> std::string
Returns a string specified word is replaced.
Definition: WeakString.cpp:418
auto hasProperty(const std::string &) const -> bool
Test wheter a property exists or not.
Definition: XML.cpp:491
auto getTag() const -> std::string
Get key; identifer of the XML.
Definition: XML.cpp:330
XML is a class representing xml object.
Definition: XML.hpp:72
void set(const Key &key, const T &val)
Set element.
Definition: HashMap.hpp:167
auto between(const WeakString &start={}, const WeakString &end={}) const -> WeakString
Generates a substring.
Definition: WeakString.cpp:194
void addAllProperty(const std::shared_ptr< XML >)
Add all properties from another XML.
Definition: XML.cpp:469
Top level namespace of products built from samchon.
Definition: ByteArray.hpp:7
A string class only references characeters, reference only.
Definition: WeakString.hpp:32