XmlParser.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * Author: Patrick-Christopher Mattulat
  3. * Company: Lynar Studios
  4. * E-Mail: webmaster@lynarstudios.com
  5. * Created: 2020-11-26
  6. * Changed: 2023-02-23
  7. *
  8. * */
  9. #include <ls-std/core/evaluator/NullPointerArgumentEvaluator.hpp>
  10. #include <ls-std/io/xml/XmlParser.hpp>
  11. using ls::std::core::Class;
  12. using ls::std::core::NullPointerArgumentEvaluator;
  13. using ls::std::core::type::byte_field;
  14. using ls::std::io::XmlAttribute;
  15. using ls::std::io::XmlDeclaration;
  16. using ls::std::io::XmlDocument;
  17. using ls::std::io::XmlNode;
  18. using ls::std::io::XmlParseMode;
  19. using ls::std::io::XmlParseParameter;
  20. using ls::std::io::XmlParser;
  21. using std::list;
  22. using std::make_shared;
  23. using std::move;
  24. using std::pair;
  25. using std::shared_ptr;
  26. using std::string;
  27. XmlParser::XmlParser(const shared_ptr<XmlDocument> &_document) : Class("XmlParser")
  28. {
  29. this->_assignDocument(_document);
  30. this->_reset();
  31. }
  32. XmlParser::~XmlParser() noexcept = default;
  33. shared_ptr<XmlDocument> XmlParser::getDocument()
  34. {
  35. return this->document;
  36. }
  37. void XmlParser::parse(const byte_field &_data)
  38. {
  39. this->_parse(_data);
  40. this->_mergeNodes();
  41. this->_reset();
  42. }
  43. void XmlParser::setDocument(const shared_ptr<XmlDocument> &_document)
  44. {
  45. this->_assignDocument(_document);
  46. }
  47. pair<string, string> XmlParser::_readAttribute_(const byte_field &_data)
  48. {
  49. return XmlParser::_parseAttribute(_data);
  50. }
  51. list<pair<string, string>> XmlParser::_readAttributes_(byte_field _data)
  52. {
  53. return XmlParser::_parseAttributes(::move(_data));
  54. }
  55. void XmlParser::_analyze(const byte_field &_data, string::size_type _index)
  56. {
  57. this->_isDeclaration(_data, _index);
  58. this->_isClosingTag(_data, _index);
  59. this->_isOpeningTag(_data, _index);
  60. this->_isValue(_data, _index);
  61. }
  62. void XmlParser::_assignDocument(const shared_ptr<XmlDocument> &_document)
  63. {
  64. NullPointerArgumentEvaluator{_document, "passed document reference is null!"}.evaluate();
  65. this->document = _document;
  66. }
  67. bool XmlParser::_contains(const string &_text, const string &_searchText)
  68. {
  69. return _text.find(_searchText) != string::npos;
  70. }
  71. shared_ptr<XmlDeclaration> XmlParser::_createDeclaration(const list<pair<string, string>> &_attributes)
  72. {
  73. shared_ptr<XmlDeclaration> declaration = make_shared<XmlDeclaration>("1.0");
  74. pair<string, string> attribute = XmlParser::_findAttribute(_attributes, "version");
  75. if (!attribute.first.empty())
  76. {
  77. declaration->setVersion(attribute.second);
  78. }
  79. attribute = XmlParser::_findAttribute(_attributes, "encoding");
  80. if (!attribute.first.empty())
  81. {
  82. declaration->setEncoding(attribute.second);
  83. }
  84. attribute = XmlParser::_findAttribute(_attributes, "standalone");
  85. if (!attribute.first.empty())
  86. {
  87. declaration->setStandalone(attribute.second);
  88. }
  89. return declaration;
  90. }
  91. shared_ptr<XmlNode> XmlParser::_createNode(const list<pair<string, string>> &_attributes, const string &_name)
  92. {
  93. shared_ptr<XmlNode> node = make_shared<XmlNode>(_name);
  94. shared_ptr<XmlAttribute> attribute{};
  95. for (const auto &parsedAttribute : _attributes)
  96. {
  97. attribute = make_shared<XmlAttribute>(parsedAttribute.first);
  98. attribute->setValue(parsedAttribute.second);
  99. node->addAttributeToEnd(attribute);
  100. }
  101. return node;
  102. }
  103. bool XmlParser::_endsWith(const string &_text, const string &_ending)
  104. {
  105. return _text.rfind(_ending) == (_text.size() - _ending.size());
  106. }
  107. pair<string, string> XmlParser::_findAttribute(const list<pair<string, string>> &_attributes, const string &_name)
  108. {
  109. pair<string, string> attribute{};
  110. for (const auto &currentAttribute : _attributes)
  111. {
  112. if (currentAttribute.first == _name)
  113. {
  114. attribute = currentAttribute;
  115. break;
  116. }
  117. }
  118. return attribute;
  119. }
  120. size_t XmlParser::_findAttributeEndPosition(const byte_field &_data)
  121. {
  122. string::size_type position = string::npos;
  123. string::size_type counter{};
  124. for (char letter : _data)
  125. {
  126. if (letter == '"')
  127. {
  128. counter++;
  129. }
  130. if (counter == 2)
  131. {
  132. break;
  133. }
  134. position++;
  135. }
  136. return position;
  137. }
  138. byte_field XmlParser::_getNextTagString(const byte_field &_data, string::size_type _index)
  139. {
  140. byte_field tag{};
  141. size_t closingCharacterPosition = _index + _data.substr(_index).find('>');
  142. if (closingCharacterPosition != string::npos)
  143. {
  144. tag = _data.substr(_index, (closingCharacterPosition - _index) + 1);
  145. }
  146. return tag;
  147. }
  148. void XmlParser::_isClosingTag(const byte_field &_data, string::size_type _index)
  149. {
  150. if (this->mode == XmlParseMode::XML_PARSE_MODE_ANALYZE && _data.substr(_index, 2) == "</")
  151. {
  152. this->mode = XmlParseMode::XML_PARSE_MODE_CLOSING_TAG;
  153. }
  154. }
  155. void XmlParser::_isDeclaration(const byte_field &_data, string::size_type _index)
  156. {
  157. if (_data.substr(_index, 5) == "<?xml")
  158. {
  159. this->mode = XmlParseMode::XML_PARSE_MODE_DECLARATION;
  160. }
  161. }
  162. void XmlParser::_isOpeningTag(const byte_field &_data, string::size_type _index)
  163. {
  164. if (this->mode == XmlParseMode::XML_PARSE_MODE_ANALYZE && _data.substr(_index, 1) == "<")
  165. {
  166. this->mode = XmlParseMode::XML_PARSE_MODE_OPENING_TAG;
  167. }
  168. }
  169. void XmlParser::_isValue(const byte_field &_data, string::size_type _index)
  170. {
  171. if (this->mode == XmlParseMode::XML_PARSE_MODE_ANALYZE)
  172. {
  173. string::size_type end = _data.substr(_index).find('<');
  174. bool isValue = _data[_index - 1] == '>' && end != string::npos && end > 0;
  175. if (isValue)
  176. {
  177. string value{_data.substr(_index, end)};
  178. if (!XmlParser::_contains(value, "\n") && !XmlParser::_contains(value, "\r\n"))
  179. {
  180. this->mode = XmlParseMode::XML_PARSE_MODE_VALUE;
  181. }
  182. }
  183. }
  184. }
  185. void XmlParser::_mergeNodes()
  186. {
  187. while (this->maxLevel > 1)
  188. {
  189. this->_mergeNodesOnCurrentLevel();
  190. this->maxLevel -= 1;
  191. }
  192. this->document->setRootElement(this->parseParameters.front().getNode());
  193. }
  194. void XmlParser::_mergeChildrenToParentNode(const shared_ptr<XmlNode> &_parent, list<XmlParseParameter>::iterator &_iterator, uint8_t _parentLevel)
  195. {
  196. do
  197. {
  198. _iterator++;
  199. if (_iterator == this->parseParameters.end())
  200. {
  201. break;
  202. }
  203. else
  204. {
  205. if (_iterator->getLevel() == this->maxLevel)
  206. {
  207. _parent->addChildToEnd(_iterator->getNode());
  208. }
  209. }
  210. } while (_iterator->getLevel() > _parentLevel);
  211. }
  212. void XmlParser::_mergeNodesOnCurrentLevel()
  213. {
  214. auto iterator = this->parseParameters.begin();
  215. uint8_t parentLevel = this->maxLevel - 1;
  216. while (iterator != this->parseParameters.end())
  217. {
  218. if (iterator->getLevel() == parentLevel)
  219. {
  220. this->_mergeChildrenToParentNode(iterator->getNode(), iterator, parentLevel);
  221. }
  222. else
  223. {
  224. iterator++;
  225. }
  226. }
  227. }
  228. void XmlParser::_parse(const byte_field &_data)
  229. {
  230. for (string::size_type index = 0; index < _data.size(); index++)
  231. {
  232. switch (this->mode)
  233. {
  234. case XmlParseMode::XML_PARSE_MODE_ANALYZE:
  235. {
  236. this->_analyze(_data, index);
  237. }
  238. break;
  239. case XmlParseMode::XML_PARSE_MODE_DECLARATION:
  240. {
  241. --index;
  242. index = this->_parseDeclaration(_data, index);
  243. this->mode = XmlParseMode::XML_PARSE_MODE_ANALYZE;
  244. }
  245. break;
  246. case XmlParseMode::XML_PARSE_MODE_OPENING_TAG:
  247. {
  248. --index;
  249. index = XmlParser::_parseOpeningTag(_data, index);
  250. this->mode = XmlParseMode::XML_PARSE_MODE_ANALYZE;
  251. }
  252. break;
  253. case XmlParseMode::XML_PARSE_MODE_VALUE:
  254. {
  255. --index;
  256. index = XmlParser::_parseValue(_data, index);
  257. this->mode = XmlParseMode::XML_PARSE_MODE_ANALYZE;
  258. }
  259. break;
  260. case XmlParseMode::XML_PARSE_MODE_CLOSING_TAG:
  261. {
  262. --index;
  263. index = XmlParser::_parseClosingTag(_data, index);
  264. this->mode = XmlParseMode::XML_PARSE_MODE_ANALYZE;
  265. }
  266. break;
  267. }
  268. }
  269. }
  270. pair<string, string> XmlParser::_parseAttribute(const byte_field &_data)
  271. {
  272. pair<string, string> parsedAttribute{};
  273. parsedAttribute.first = _data.substr(0, _data.find('='));
  274. parsedAttribute.second = _data.substr(_data.find('"') + 1);
  275. parsedAttribute.second.pop_back();
  276. return parsedAttribute;
  277. }
  278. list<pair<string, string>> XmlParser::_parseAttributes(byte_field _data)
  279. {
  280. list<pair<string, string>> attributes{};
  281. size_t position = _data.find(' ');
  282. _data = position == string::npos ? "" : _data.substr(position);
  283. while (!_data.empty())
  284. {
  285. do
  286. {
  287. position = _data.find(' ') + 1;
  288. } while (_data[position] == ' ');
  289. if (_data.size() <= 3 && XmlParser::_endsWith(string{_data}, ">"))
  290. {
  291. break;
  292. }
  293. string attributeString = _data.substr(position, XmlParser::_findAttributeEndPosition(_data) + 1);
  294. attributes.push_back(XmlParser::_parseAttribute(attributeString));
  295. _data = _data.substr(position + attributeString.size());
  296. }
  297. return attributes;
  298. }
  299. size_t XmlParser::_parseClosingTag(const byte_field &_data, string::size_type _index)
  300. {
  301. string tagString = XmlParser::_getNextTagString(_data, _index);
  302. this->currentLevel -= 1;
  303. return tagString.empty() ? _index : _index + (tagString.size() - 1);
  304. }
  305. size_t XmlParser::_parseDeclaration(const byte_field &_data, string::size_type _index)
  306. {
  307. string tagString = XmlParser::_getNextTagString(_data, _index);
  308. bool isValidTagString = !tagString.empty();
  309. if (isValidTagString)
  310. {
  311. shared_ptr<XmlDeclaration> declaration = this->_createDeclaration(XmlParser::_parseAttributes(tagString));
  312. this->document->setDeclaration(declaration);
  313. }
  314. return !isValidTagString ? _index : _index + (tagString.size() - 1);
  315. }
  316. size_t XmlParser::_parseOpeningTag(const byte_field &_data, string::size_type _index)
  317. {
  318. string tagString{XmlParser::_getNextTagString(_data, _index)};
  319. bool isValidTagString = !tagString.empty();
  320. XmlParseParameter singleParseParameter{};
  321. if (isValidTagString)
  322. {
  323. shared_ptr<XmlNode> node = XmlParser::_createNode(XmlParser::_parseAttributes(tagString), XmlParser::_parseTagName(tagString));
  324. singleParseParameter.setLevel(this->currentLevel);
  325. singleParseParameter.setNode(node);
  326. this->parseParameters.push_back(singleParseParameter);
  327. if (!XmlParser::_endsWith(tagString, "/>"))
  328. {
  329. this->currentLevel += 1;
  330. this->_setMaxLevel();
  331. }
  332. }
  333. return !isValidTagString ? _index : _index + (tagString.size() - 1);
  334. }
  335. byte_field XmlParser::_parseTagName(const byte_field &_data)
  336. {
  337. string::size_type position = _data.find(' ');
  338. if (position == string::npos)
  339. {
  340. position = _data.find('>');
  341. }
  342. return _data.substr(1, position - 1);
  343. }
  344. size_t XmlParser::_parseValue(const byte_field &_data, string::size_type _index)
  345. {
  346. byte_field value = _data.substr(_index, _data.substr(_index).find('<'));
  347. this->parseParameters.back().getNode()->setValue(value);
  348. return _index + (value.size() - 1);
  349. }
  350. void XmlParser::_reset()
  351. {
  352. this->currentLevel = 1;
  353. this->maxLevel = 1;
  354. this->mode = XmlParseMode::XML_PARSE_MODE_ANALYZE;
  355. this->parseParameters.clear();
  356. }
  357. void XmlParser::_setMaxLevel()
  358. {
  359. if (this->currentLevel > this->maxLevel)
  360. {
  361. this->maxLevel = this->currentLevel;
  362. }
  363. }