diff options
author | crupest <crupest@outlook.com> | 2022-01-02 18:49:31 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2022-01-02 18:49:31 +0800 |
commit | 18099ad8f5c24b1c2b1c92238dbc54912eab0406 (patch) | |
tree | 514207d630a2100262aedaea276ea259bbc108b7 /src/xml | |
parent | 96a93e17baaff2c2050eba2afada639e93001232 (diff) | |
download | cru-18099ad8f5c24b1c2b1c92238dbc54912eab0406.tar.gz cru-18099ad8f5c24b1c2b1c92238dbc54912eab0406.tar.bz2 cru-18099ad8f5c24b1c2b1c92238dbc54912eab0406.zip |
...
Diffstat (limited to 'src/xml')
-rw-r--r-- | src/xml/XmlNode.cpp | 6 | ||||
-rw-r--r-- | src/xml/XmlParser.cpp | 115 |
2 files changed, 97 insertions, 24 deletions
diff --git a/src/xml/XmlNode.cpp b/src/xml/XmlNode.cpp index f4b43ea6..d6203973 100644 --- a/src/xml/XmlNode.cpp +++ b/src/xml/XmlNode.cpp @@ -1,6 +1,12 @@ #include "cru/xml/XmlNode.hpp" namespace cru::xml { +XmlElementNode::~XmlElementNode() { + for (auto child : children_) { + delete child; + } +} + void XmlElementNode::AddAttribute(String key, String value) { attributes_[std::move(key)] = std::move(value); } diff --git a/src/xml/XmlParser.cpp b/src/xml/XmlParser.cpp index f24a7f68..d0f61542 100644 --- a/src/xml/XmlParser.cpp +++ b/src/xml/XmlParser.cpp @@ -2,6 +2,10 @@ #include "cru/xml/XmlNode.hpp" namespace cru::xml { +XmlParser::XmlParser(String xml) : xml_(std::move(xml)) {} + +XmlParser::~XmlParser() { delete pseudo_root_node_; } + XmlElementNode* XmlParser::Parse() { if (!cache_) { cache_ = DoParse(); @@ -16,6 +20,13 @@ char16_t XmlParser::Read1() { return xml_[current_position_++]; } +String XmlParser::ReadWithoutAdvance(int count) { + if (current_position_ + count > xml_.size()) { + return u""; + } + return xml_.substr(current_position_, count); +} + void XmlParser::ReadSpacesAndDiscard() { while (current_position_ < xml_.size() && (xml_[current_position_] == ' ' || xml_[current_position_] == '\t' || @@ -70,48 +81,104 @@ String XmlParser::ReadAttributeString() { XmlElementNode* XmlParser::DoParse() { while (current_position_ < xml_.size()) { - switch (xml_[current_position_]) { - case '<': { - ++current_position_; + ReadSpacesAndDiscard(); - if (Read1() == '/') { - } else { - ReadSpacesAndDiscard(); + if (current_position_ == xml_.size()) { + break; + } - String tag = ReadIdenitifier(); + if (ReadWithoutAdvance() == u"<") { + current_position_ += 1; - XmlElementNode* node = new XmlElementNode(tag); + if (ReadWithoutAdvance() == u"/") { + current_position_ += 1; - while (true) { - ReadSpacesAndDiscard(); - if (Read1() == '>') { - break; - } else { - String attribute_name = ReadIdenitifier(); + ReadSpacesAndDiscard(); + + String tag = ReadIdenitifier(); + + if (tag != current_->GetTag()) { + throw XmlParsingException(u"Tag mismatch."); + } + + ReadSpacesAndDiscard(); + + if (Read1() != '>') { + throw XmlParsingException(u"Expected >."); + } + + current_ = current_->GetParent(); + } else { + ReadSpacesAndDiscard(); + + String tag = ReadIdenitifier(); + + XmlElementNode* node = new XmlElementNode(tag); - ReadSpacesAndDiscard(); + bool is_self_closing = false; - if (Read1() != '=') { - throw XmlParsingException(u"Expected '='"); - } + while (true) { + ReadSpacesAndDiscard(); + auto c = ReadWithoutAdvance(); + if (c == u">") { + current_position_ += 1; + break; + } else if (c == u"/") { + current_position_ += 1; + + if (Read1() != '>') { + throw XmlParsingException(u"Expected >."); + } - ReadSpacesAndDiscard(); + is_self_closing = true; + break; + } else { + String attribute_name = ReadIdenitifier(); - String attribute_value = ReadAttributeString(); + ReadSpacesAndDiscard(); - node->AddAttribute(attribute_name, attribute_value); + if (Read1() != '=') { + throw XmlParsingException(u"Expected '='"); } + + ReadSpacesAndDiscard(); + + String attribute_value = ReadAttributeString(); + + node->AddAttribute(attribute_name, attribute_value); } + } + + current_->AddChild(node); - current_->AddChild(node); + if (!is_self_closing) { current_ = node; } + } + + } else { + String text; + + while (ReadWithoutAdvance() != u"<") { + char16_t c = Read1(); - break; + text += c; } + + if (!text.empty()) current_->AddChild(new XmlTextNode(text.TrimEnd())); } } - return pseudo_root_node_; + if (current_ != pseudo_root_node_) { + throw XmlParsingException(u"Unexpected end of xml"); + } + + if (pseudo_root_node_->GetChildren().size() != 1 || + pseudo_root_node_->GetChildren()[0]->GetType() != + XmlNode::Type::Element) { + throw XmlParsingException(u"Expected 1 element node as root."); + } + + return static_cast<XmlElementNode*>(pseudo_root_node_->GetChildren()[0]); } } // namespace cru::xml |