Просмотр исходного кода

Extended XMLReader class (incomplete)

- XMLReader class now successfully parses nodes and
already adds attributes
- missing:
  - node name
  - add nodes to document
  - value parsing
Patrick 4 лет назад
Родитель
Сommit
65349ca6fc
3 измененных файлов с 136 добавлено и 21 удалено
  1. 118 19
      source/io/xml/XMLReader.cpp
  2. 16 1
      source/io/xml/XMLReader.hpp
  3. 2 1
      test/cases/io/xml/XMLReaderTest.cpp

+ 118 - 19
source/io/xml/XMLReader.cpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2020-10-10
- * Changed:         2020-10-16
+ * Changed:         2020-10-18
  *
  * */
 
@@ -11,7 +11,6 @@
 #include "../../exception/IllegalArgumentException.hpp"
 #include "../FileReader.hpp"
 #include "../../boxing/String.hpp"
-#include <vector>
 
 ls_std::XMLReader::XMLReader(const std::shared_ptr<ls_std::XMLDocument>& _document, const std::string& _absolutePath) :
 Class("XMLReader"),
@@ -26,6 +25,7 @@ ls_std::byte_field ls_std::XMLReader::read()
 {
   ls_std::byte_field data = ls_std::FileReader {this->xmlFile}.read();
   this->_read(data);
+  this->_reset();
 
   return data;
 }
@@ -41,6 +41,23 @@ void ls_std::XMLReader::setFile(const ls_std::File &_xmlFile)
   this->xmlFile = _xmlFile;
 }
 
+std::pair<std::string, std::string> ls_std::XMLReader::_readAttribute_(const ls_std::byte_field &_data)
+{
+  return ls_std::XMLReader::_readAttribute(_data);
+}
+
+std::list<std::pair<std::string, std::string>> ls_std::XMLReader::_readAttributes_(ls_std::byte_field _data)
+{
+  return ls_std::XMLReader::_readAttributes(std::move(_data));
+}
+
+void ls_std::XMLReader::_analyze(const ls_std::byte_field &_data, std::string::size_type _index)
+{
+  this->_isDeclaration(_data, _index);
+  this->_isClosingTag(_data, _index);
+  this->_isOpeningTag(_data, _index);
+}
+
 void ls_std::XMLReader::_checkDocumentExistence(const std::shared_ptr<ls_std::XMLDocument>& _document)
 {
   if(_document == nullptr) {
@@ -79,6 +96,20 @@ std::shared_ptr<ls_std::XMLDeclaration> ls_std::XMLReader::_createDeclaration(co
   return declaration;
 }
 
+std::shared_ptr<ls_std::XMLNode> ls_std::XMLReader::_createNode(const std::list<std::pair<std::string, std::string>> &_attributes)
+{
+  std::shared_ptr<ls_std::XMLNode> node = std::make_shared<ls_std::XMLNode>("_creation_token_");
+  std::shared_ptr<ls_std::XMLAttribute> attribute {};
+
+  for(const auto& parsedAttribute : _attributes) {
+    attribute = std::make_shared<ls_std::XMLAttribute>(parsedAttribute.first);
+    attribute->setValue(parsedAttribute.second);
+    node->addAttributeToEnd(attribute);
+  }
+
+  return node;
+}
+
 std::pair<std::string, std::string> ls_std::XMLReader::_findAttribute(const std::list<std::pair<std::string, std::string>> &_attributes, const std::string &_name)
 {
   std::pair<std::string, std::string> attribute {};
@@ -93,6 +124,26 @@ std::pair<std::string, std::string> ls_std::XMLReader::_findAttribute(const std:
   return attribute;
 }
 
+size_t ls_std::XMLReader::_findAttributeEndPosition(const ls_std::byte_field &_data)
+{
+  std::string::size_type position = std::string::npos;
+  std::string::size_type counter {};
+
+  for(char letter : _data) {
+    if(letter == '"') {
+      counter++;
+    }
+
+    if(counter == 2) {
+      break;
+    }
+
+    position++;
+  }
+
+  return position;
+}
+
 void ls_std::XMLReader::_isClosingTag(const ls_std::byte_field &_data, std::string::size_type _index)
 {
   if(this->mode == XML_PARSE_MODE_ANALYZE && _data.substr(_index, 2) == "</") {
@@ -120,23 +171,25 @@ void ls_std::XMLReader::_read(const ls_std::byte_field &_data)
     switch(this->mode) {
       case XML_PARSE_MODE_ANALYZE:
       {
-        this->_isDeclaration(_data, index);
-        this->_isClosingTag(_data, index);
-        this->_isOpeningTag(_data, index);
+        this->_analyze(_data, index);
       } break;
       case XML_PARSE_MODE_DECLARATION:
       {
         --index;
-        index = ls_std::XMLReader::_readDeclaration(_data, index);
+        index = this->_readDeclaration(_data, index);
         this->mode = XML_PARSE_MODE_ANALYZE;
       } break;
       case XML_PARSE_MODE_OPENING_TAG:
       {
-
+        --index;
+        index = ls_std::XMLReader::_readOpeningTag(_data, index);
+        this->mode = XML_PARSE_MODE_ANALYZE;
       } break;
       case XML_PARSE_MODE_CLOSING_TAG:
       {
-
+        --index;
+        index = ls_std::XMLReader::_readClosingTag(_data, index);
+        this->mode = XML_PARSE_MODE_ANALYZE;
       } break;
     }
   }
@@ -155,37 +208,83 @@ std::pair<std::string, std::string> ls_std::XMLReader::_readAttribute(const ls_s
 std::list<std::pair<std::string, std::string>> ls_std::XMLReader::_readAttributes(ls_std::byte_field _data)
 {
   std::list<std::pair<std::string, std::string>> attributes {};
-  size_t attributePosition;
-  _data = _data.substr(5);
+  size_t position = _data.find(' ');
+  _data = position == std::string::npos ? "" : _data.substr(position);
 
   while(!_data.empty()) {
     do {
-      attributePosition = _data.find(' ') + 1;
+      position = _data.find(' ') + 1;
     }
-    while(_data[attributePosition] == ' ');
+    while(_data[position] == ' ');
 
     if(_data.size() <= 3 && ls_std::String {_data}.endsWith(">")) {
       break;
     }
 
-    std::string attributeString = _data.substr(attributePosition, _data.find(R"(" )"));
+    std::string attributeString = _data.substr(position, ls_std::XMLReader::_findAttributeEndPosition(_data) + 1);
     attributes.push_back(ls_std::XMLReader::_readAttribute(attributeString));
-    _data = _data.substr(attributePosition + attributeString.size());
+    _data = _data.substr(position + attributeString.size());
   }
 
   return attributes;
 }
 
+size_t ls_std::XMLReader::_readClosingTag(const ls_std::byte_field &_data, std::string::size_type _index)
+{
+  std::string tagString = ls_std::XMLReader::_readTag(_data, _index);
+  this->currentLevel -= 1;
+  return tagString.empty() ? _index : _index + tagString.size();
+}
+
 size_t ls_std::XMLReader::_readDeclaration(const ls_std::byte_field &_data, std::string::size_type _index)
 {
-  size_t closingTagPosition = _data.find('>');
+  std::string tagString = ls_std::XMLReader::_readTag(_data, _index);
+  bool isValidTagString = !tagString.empty();
 
-  if(closingTagPosition != std::string::npos) {
-    std::string declarationString = _data.substr(_index, (closingTagPosition - _index) + 1);
-    std::shared_ptr<ls_std::XMLDeclaration> declaration = this->_createDeclaration(ls_std::XMLReader::_readAttributes(declarationString));
+  if(isValidTagString) {
+    std::shared_ptr<ls_std::XMLDeclaration> declaration = this->_createDeclaration(ls_std::XMLReader::_readAttributes(tagString));
     this->document->setDeclaration(declaration);
   }
 
-  return (closingTagPosition == std::string::npos) ? _index : closingTagPosition;
+  return !isValidTagString ? _index : _index + tagString.size();
+}
+
+size_t ls_std::XMLReader::_readOpeningTag(const ls_std::byte_field &_data, std::string::size_type _index)
+{
+  ls_std::String tagString {ls_std::XMLReader::_readTag(_data, _index)};
+  bool isValidTagString = !tagString.toString().empty();
+  ls_std::XMLParseData singleParseData {};
+
+  if(isValidTagString) {
+    std::shared_ptr<ls_std::XMLNode> node = ls_std::XMLReader::_createNode(ls_std::XMLReader::_readAttributes(tagString));
+
+    if(!tagString.endsWith("/>")) {
+      this->currentLevel += 1;
+    }
+
+    singleParseData.level = this->currentLevel;
+    singleParseData.node = node;
+    this->parseData.push_back(singleParseData);
+  }
+
+  return !isValidTagString ? _index : _index + tagString.toString().size();
 }
 
+ls_std::byte_field ls_std::XMLReader::_readTag(const ls_std::byte_field &_data, std::string::size_type _index)
+{
+  ls_std::byte_field tag {};
+  size_t closingCharacterPosition = _index + _data.substr(_index).find('>');
+
+  if(closingCharacterPosition != std::string::npos) {
+    tag = _data.substr(_index, (closingCharacterPosition - _index) + 1);
+  }
+
+  return tag;
+}
+
+void ls_std::XMLReader::_reset()
+{
+  this->currentLevel = 0;
+  this->mode = XML_PARSE_MODE_ANALYZE;
+  this->parseData.clear();
+}

+ 16 - 1
source/io/xml/XMLReader.hpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2020-10-08
- * Changed:         2020-10-16
+ * Changed:         2020-10-18
  *
  * */
 
@@ -15,6 +15,7 @@
 #include "../IReader.hpp"
 #include "../File.hpp"
 #include "XMLParseMode.hpp"
+#include "XMLParseData.hpp"
 #include <list>
 
 namespace ls_std {
@@ -33,23 +34,37 @@ namespace ls_std {
       std::shared_ptr<ls_std::XMLDocument> getDocument();
       void setFile(const ls_std::File& _xmlFile);
 
+    protected:
+
+      static std::pair<std::string, std::string> _readAttribute_(const ls_std::byte_field& _data);
+      static std::list<std::pair<std::string, std::string>> _readAttributes_(ls_std::byte_field _data);
+
     private:
 
+      uint8_t currentLevel {};
       std::shared_ptr<ls_std::XMLDocument> document {};
       ls_std::XMLParseMode mode {};
+      std::list<ls_std::XMLParseData> parseData {};
       ls_std::File xmlFile;
 
+      void _analyze(const ls_std::byte_field &_data, std::string::size_type _index);
       static void _checkDocumentExistence(const std::shared_ptr<ls_std::XMLDocument>& _document);
       static void _checkFileExistence(ls_std::File _xmlFile);
       static std::shared_ptr<ls_std::XMLDeclaration> _createDeclaration(const std::list<std::pair<std::string, std::string>>& _attributes);
+      static std::shared_ptr<ls_std::XMLNode> _createNode(const std::list<std::pair<std::string, std::string>>& _attributes);
       static std::pair<std::string, std::string> _findAttribute(const std::list<std::pair<std::string, std::string>>& _attributes, const std::string& _name);
+      static size_t _findAttributeEndPosition(const ls_std::byte_field& _data);
       void _isClosingTag(const ls_std::byte_field& _data, std::string::size_type _index);
       void _isDeclaration(const ls_std::byte_field& _data, std::string::size_type _index);
       void _isOpeningTag(const ls_std::byte_field& _data, std::string::size_type _index);
       void _read(const ls_std::byte_field& _data);
       static std::pair<std::string, std::string> _readAttribute(const ls_std::byte_field& _data);
       static std::list<std::pair<std::string, std::string>> _readAttributes(ls_std::byte_field _data);
+      size_t _readClosingTag(const ls_std::byte_field& _data, std::string::size_type _index);
       size_t _readDeclaration(const ls_std::byte_field& _data, std::string::size_type _index);
+      size_t _readOpeningTag(const ls_std::byte_field& _data, std::string::size_type _index);
+      static ls_std::byte_field _readTag(const ls_std::byte_field& _data, std::string::size_type _index);
+      void _reset();
   };
 }
 

+ 2 - 1
test/cases/io/xml/XMLReaderTest.cpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2020-10-10
- * Changed:         2020-10-16
+ * Changed:         2020-10-18
  *
  * */
 
@@ -33,6 +33,7 @@ namespace {
 
     ASSERT_STREQ("UTF-8", xmlReader.getDocument()->getDeclaration()->getEncoding().c_str());
     ASSERT_STREQ("1.0", xmlReader.getDocument()->getDeclaration()->getVersion().c_str());
+    ASSERT_TRUE(xmlReader.getDocument()->getDeclaration()->getStandalone().empty());
   }
 
   TEST_F(XMLReaderTest, getDocument)