From 1a6111e3f02b0a9cff0f81fb524b4dfb7d69854b Mon Sep 17 00:00:00 2001 From: Yuqian Yang Date: Tue, 4 Nov 2025 21:59:42 +0800 Subject: Move xml to base. --- src/CMakeLists.txt | 1 - src/base/CMakeLists.txt | 2 + src/base/xml/XmlNode.cpp | 75 +++++++++ src/base/xml/XmlParser.cpp | 197 +++++++++++++++++++++++ src/ui/CMakeLists.txt | 2 +- src/ui/ThemeResourceDictionary.cpp | 4 +- src/ui/mapper/BorderStyleMapper.cpp | 2 +- src/ui/mapper/BrushMapper.cpp | 2 +- src/ui/mapper/StringMapper.cpp | 2 +- src/ui/mapper/ThicknessMapper.cpp | 2 +- src/ui/mapper/style/AndConditionMapper.cpp | 2 +- src/ui/mapper/style/BorderStylerMapper.cpp | 2 +- src/ui/mapper/style/CheckedConditionMapper.cpp | 2 +- src/ui/mapper/style/ContentBrushStylerMapper.cpp | 2 +- src/ui/mapper/style/FocusConditionMapper.cpp | 2 +- src/ui/mapper/style/NoConditionMapper.cpp | 2 +- src/ui/mapper/style/OrConditionMapper.cpp | 2 +- src/xml/CMakeLists.txt | 6 - src/xml/XmlNode.cpp | 76 --------- src/xml/XmlParser.cpp | 196 ---------------------- 20 files changed, 288 insertions(+), 293 deletions(-) create mode 100644 src/base/xml/XmlNode.cpp create mode 100644 src/base/xml/XmlParser.cpp delete mode 100644 src/xml/CMakeLists.txt delete mode 100644 src/xml/XmlNode.cpp delete mode 100644 src/xml/XmlParser.cpp (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 959f2dd1..9f9c205f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,5 @@ add_subdirectory(platform) add_subdirectory(ui) add_subdirectory(parse) add_subdirectory(toml) -add_subdirectory(xml) add_subdirectory(ThemeBuilder) diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index be45d0e0..ef5afe3c 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -14,6 +14,8 @@ add_library(CruBase io/MemoryStream.cpp log/Logger.cpp log/StdioLogTarget.cpp + xml/XmlNode.cpp + xml/XmlParser.cpp ) target_compile_definitions(CruBase PRIVATE CRU_BASE_EXPORT_API) target_include_directories(CruBase PUBLIC ${CRU_INCLUDE_DIR}) diff --git a/src/base/xml/XmlNode.cpp b/src/base/xml/XmlNode.cpp new file mode 100644 index 00000000..d3e7369b --- /dev/null +++ b/src/base/xml/XmlNode.cpp @@ -0,0 +1,75 @@ +#include "cru/base/xml/XmlNode.h" + +#include + +namespace cru::xml { + +XmlElementNode* XmlNode::AsElement() { + return static_cast(this); +} + +XmlTextNode* XmlNode::AsText() { return static_cast(this); } + +XmlCommentNode* XmlNode::AsComment() { + return static_cast(this); +} + +const XmlElementNode* XmlNode::AsElement() const { + return static_cast(this); +} + +const XmlTextNode* XmlNode::AsText() const { + return static_cast(this); +} + +const XmlCommentNode* XmlNode::AsComment() const { + return static_cast(this); +} + +XmlElementNode::~XmlElementNode() { + for (auto child : children_) { + delete child; + } +} + +void XmlElementNode::AddAttribute(std::string key, std::string value) { + attributes_[std::move(key)] = std::move(value); +} + +void XmlElementNode::AddChild(XmlNode* child) { + Expects(child->GetParent() == nullptr); + children_.push_back(child); + child->parent_ = this; +} + +Index XmlElementNode::GetChildElementCount() const { + return std::count_if( + children_.cbegin(), children_.cend(), + [](xml::XmlNode* node) { return node->IsElementNode(); }); +} + +XmlElementNode* XmlElementNode::GetFirstChildElement() const { + for (auto child : children_) { + if (child->GetType() == XmlNode::Type::Element) { + return child->AsElement(); + } + } + return nullptr; +} + +XmlNode* XmlElementNode::Clone() const { + XmlElementNode* node = new XmlElementNode(tag_, attributes_); + + for (auto child : children_) { + node->AddChild(child->Clone()); + } + + return node; +} + +XmlNode* XmlCommentNode::Clone() const { + XmlCommentNode* node = new XmlCommentNode(text_); + + return node; +} +} // namespace cru::xml diff --git a/src/base/xml/XmlParser.cpp b/src/base/xml/XmlParser.cpp new file mode 100644 index 00000000..c35d7a7b --- /dev/null +++ b/src/base/xml/XmlParser.cpp @@ -0,0 +1,197 @@ +#include "cru/base/xml/XmlParser.h" +#include "cru/base/StringUtil.h" +#include "cru/base/xml/XmlNode.h" + +namespace cru::xml { +XmlParser::XmlParser(std::string xml) : xml_(std::move(xml)) {} + +XmlParser::~XmlParser() { delete pseudo_root_node_; } + +XmlElementNode* XmlParser::Parse() { + if (!cache_) { + cache_ = DoParse(); + } + return static_cast(cache_->Clone()); +} + +char16_t XmlParser::Read1() { + if (current_position_ >= xml_.size()) { + throw XmlParsingException("Unexpected end of xml"); + } + return xml_[current_position_++]; +} + +std::string XmlParser::ReadWithoutAdvance(int count) { + if (current_position_ + count > xml_.size()) { + count = xml_.size() - current_position_; + } + return xml_.substr(current_position_, count); +} + +void XmlParser::ReadSpacesAndDiscard() { + while (current_position_ < xml_.size() && + (xml_[current_position_] == ' ' || xml_[current_position_] == '\t' || + xml_[current_position_] == '\n' || xml_[current_position_] == '\r')) { + ++current_position_; + } +} + +std::string XmlParser::ReadSpaces() { + std::string spaces; + while (current_position_ < xml_.size() && + (xml_[current_position_] == ' ' || xml_[current_position_] == '\t' || + xml_[current_position_] == '\n' || xml_[current_position_] == '\r')) { + spaces += xml_[current_position_]; + ++current_position_; + } + return spaces; +} + +std::string XmlParser::ReadIdenitifier() { + std::string identifier; + while (current_position_ < xml_.size() && + (xml_[current_position_] >= 'a' && xml_[current_position_] <= 'z' || + xml_[current_position_] >= 'A' && xml_[current_position_] <= 'Z' || + xml_[current_position_] >= '0' && xml_[current_position_] <= '9' || + xml_[current_position_] == '_')) { + identifier += xml_[current_position_]; + ++current_position_; + } + return identifier; +} + +std::string XmlParser::ReadAttributeString() { + if (Read1() != '"') { + throw XmlParsingException("Expected \"."); + } + + std::string string; + + while (true) { + char16_t c = Read1(); + + if (c == '"') { + break; + } + + string += c; + } + + return string; +} + +XmlElementNode* XmlParser::DoParse() { + while (current_position_ < xml_.size()) { + ReadSpacesAndDiscard(); + + if (current_position_ == xml_.size()) { + break; + } + + if (ReadWithoutAdvance() == "<") { + current_position_ += 1; + + if (ReadWithoutAdvance() == "/") { + current_position_ += 1; + + ReadSpacesAndDiscard(); + + std::string tag = ReadIdenitifier(); + + if (tag != current_->GetTag()) { + throw XmlParsingException("Tag mismatch."); + } + + ReadSpacesAndDiscard(); + + if (Read1() != '>') { + throw XmlParsingException("Expected >."); + } + + current_ = current_->GetParent(); + } else if (ReadWithoutAdvance(3) == "!--") { + current_position_ += 3; + + std::string text; + while (true) { + auto str = ReadWithoutAdvance(3); + if (str == "-->") break; + if (str.empty()) throw XmlParsingException("Unexpected end of xml"); + text += Read1(); + } + + current_position_ += 3; + current_->AddChild(new XmlCommentNode(cru::string::Trim(text))); + } else { + ReadSpacesAndDiscard(); + + std::string tag = ReadIdenitifier(); + + XmlElementNode* node = new XmlElementNode(tag); + + bool is_self_closing = false; + + while (true) { + ReadSpacesAndDiscard(); + auto c = ReadWithoutAdvance(); + if (c == ">") { + current_position_ += 1; + break; + } else if (c == "/") { + current_position_ += 1; + + if (Read1() != '>') { + throw XmlParsingException("Expected >."); + } + + is_self_closing = true; + break; + } else { + std::string attribute_name = ReadIdenitifier(); + + ReadSpacesAndDiscard(); + + if (Read1() != '=') { + throw XmlParsingException("Expected '='"); + } + + ReadSpacesAndDiscard(); + + std::string attribute_value = ReadAttributeString(); + + node->AddAttribute(attribute_name, attribute_value); + } + } + + current_->AddChild(node); + + if (!is_self_closing) { + current_ = node; + } + } + + } else { + std::string text; + + while (ReadWithoutAdvance() != "<") { + char16_t c = Read1(); + + text += c; + } + + if (!text.empty()) + current_->AddChild(new XmlTextNode(cru::string::TrimEnd(text))); + } + } + + if (current_ != pseudo_root_node_) { + throw XmlParsingException("Unexpected end of xml"); + } + + if (pseudo_root_node_->GetChildren().size() != 1) { + throw XmlParsingException("Expected 1 node as root."); + } + + return static_cast(pseudo_root_node_->GetChildren()[0]); +} +} // namespace cru::xml diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 93077388..4dfee0cb 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -79,4 +79,4 @@ add_library(CruUi style/StyleRuleSet.cpp ) target_compile_definitions(CruUi PRIVATE CRU_UI_EXPORT_API) -target_link_libraries(CruUi PUBLIC CruPlatformGui CruXml) +target_link_libraries(CruUi PUBLIC CruPlatformGui) diff --git a/src/ui/ThemeResourceDictionary.cpp b/src/ui/ThemeResourceDictionary.cpp index b9c7c284..9f734054 100644 --- a/src/ui/ThemeResourceDictionary.cpp +++ b/src/ui/ThemeResourceDictionary.cpp @@ -2,8 +2,8 @@ #include "cru/base/StringUtil.h" #include "cru/base/io/CFileStream.h" #include "cru/base/log/Logger.h" -#include "cru/xml/XmlNode.h" -#include "cru/xml/XmlParser.h" +#include "cru/base/xml/XmlNode.h" +#include "cru/base/xml/XmlParser.h" namespace cru::ui { diff --git a/src/ui/mapper/BorderStyleMapper.cpp b/src/ui/mapper/BorderStyleMapper.cpp index fa3f672d..d4889457 100644 --- a/src/ui/mapper/BorderStyleMapper.cpp +++ b/src/ui/mapper/BorderStyleMapper.cpp @@ -3,7 +3,7 @@ #include "cru/platform/graphics/Brush.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/style/ApplyBorderStyleInfo.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper { using namespace xml; diff --git a/src/ui/mapper/BrushMapper.cpp b/src/ui/mapper/BrushMapper.cpp index 81eb40a5..4f17bd12 100644 --- a/src/ui/mapper/BrushMapper.cpp +++ b/src/ui/mapper/BrushMapper.cpp @@ -5,7 +5,7 @@ #include "cru/platform/graphics/Brush.h" #include "cru/platform/graphics/Factory.h" #include "cru/ui/mapper/MapperRegistry.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" #include diff --git a/src/ui/mapper/StringMapper.cpp b/src/ui/mapper/StringMapper.cpp index 6f6b4546..24b79ff4 100644 --- a/src/ui/mapper/StringMapper.cpp +++ b/src/ui/mapper/StringMapper.cpp @@ -1,5 +1,5 @@ #include "cru/ui/mapper/StringMapper.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper { StringMapper::StringMapper() { SetAllowedTags({"String"}); } diff --git a/src/ui/mapper/ThicknessMapper.cpp b/src/ui/mapper/ThicknessMapper.cpp index e6557689..2dc6efdc 100644 --- a/src/ui/mapper/ThicknessMapper.cpp +++ b/src/ui/mapper/ThicknessMapper.cpp @@ -1,6 +1,6 @@ #include "cru/ui/mapper/ThicknessMapper.h" #include "cru/base/StringUtil.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper { bool ThicknessMapper::XmlElementIsOfThisType(xml::XmlElementNode* node) { diff --git a/src/ui/mapper/style/AndConditionMapper.cpp b/src/ui/mapper/style/AndConditionMapper.cpp index c1b7e5e5..0b1fc008 100644 --- a/src/ui/mapper/style/AndConditionMapper.cpp +++ b/src/ui/mapper/style/AndConditionMapper.cpp @@ -3,7 +3,7 @@ #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/mapper/style/IConditionMapper.h" #include "cru/ui/style/Condition.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper::style { bool AndConditionMapper::XmlElementIsOfThisType(xml::XmlElementNode *node) { diff --git a/src/ui/mapper/style/BorderStylerMapper.cpp b/src/ui/mapper/style/BorderStylerMapper.cpp index e93a0af8..3deeed43 100644 --- a/src/ui/mapper/style/BorderStylerMapper.cpp +++ b/src/ui/mapper/style/BorderStylerMapper.cpp @@ -3,7 +3,7 @@ #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/style/ApplyBorderStyleInfo.h" #include "cru/ui/style/Styler.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper::style { using cru::ui::style::ApplyBorderStyleInfo; diff --git a/src/ui/mapper/style/CheckedConditionMapper.cpp b/src/ui/mapper/style/CheckedConditionMapper.cpp index aafc97a4..2d01b4bf 100644 --- a/src/ui/mapper/style/CheckedConditionMapper.cpp +++ b/src/ui/mapper/style/CheckedConditionMapper.cpp @@ -2,7 +2,7 @@ #include "cru/base/ClonablePtr.h" #include "cru/base/StringUtil.h" #include "cru/ui/style/Condition.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper::style { bool CheckedConditionMapper::XmlElementIsOfThisType(xml::XmlElementNode* node) { diff --git a/src/ui/mapper/style/ContentBrushStylerMapper.cpp b/src/ui/mapper/style/ContentBrushStylerMapper.cpp index 027622fe..c5caab02 100644 --- a/src/ui/mapper/style/ContentBrushStylerMapper.cpp +++ b/src/ui/mapper/style/ContentBrushStylerMapper.cpp @@ -3,7 +3,7 @@ #include "cru/platform/graphics/Brush.h" #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/style/Styler.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper::style { ContentBrushStylerMapper::ContentBrushStylerMapper() { diff --git a/src/ui/mapper/style/FocusConditionMapper.cpp b/src/ui/mapper/style/FocusConditionMapper.cpp index b21ac250..26a5780d 100644 --- a/src/ui/mapper/style/FocusConditionMapper.cpp +++ b/src/ui/mapper/style/FocusConditionMapper.cpp @@ -2,7 +2,7 @@ #include "cru/base/ClonablePtr.h" #include "cru/base/StringUtil.h" #include "cru/ui/style/Condition.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper::style { bool FocusConditionMapper::XmlElementIsOfThisType(xml::XmlElementNode* node) { diff --git a/src/ui/mapper/style/NoConditionMapper.cpp b/src/ui/mapper/style/NoConditionMapper.cpp index d38e187b..84cbf598 100644 --- a/src/ui/mapper/style/NoConditionMapper.cpp +++ b/src/ui/mapper/style/NoConditionMapper.cpp @@ -1,6 +1,6 @@ #include "cru/ui/mapper/style/NoConditionMapper.h" #include "cru/base/ClonablePtr.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper::style { bool NoConditionMapper::XmlElementIsOfThisType(xml::XmlElementNode* node) { diff --git a/src/ui/mapper/style/OrConditionMapper.cpp b/src/ui/mapper/style/OrConditionMapper.cpp index 9c983d83..98b4078d 100644 --- a/src/ui/mapper/style/OrConditionMapper.cpp +++ b/src/ui/mapper/style/OrConditionMapper.cpp @@ -3,7 +3,7 @@ #include "cru/ui/mapper/MapperRegistry.h" #include "cru/ui/mapper/style/IConditionMapper.h" #include "cru/ui/style/Condition.h" -#include "cru/xml/XmlNode.h" +#include "cru/base/xml/XmlNode.h" namespace cru::ui::mapper::style { bool OrConditionMapper::XmlElementIsOfThisType(xml::XmlElementNode *node) { diff --git a/src/xml/CMakeLists.txt b/src/xml/CMakeLists.txt deleted file mode 100644 index 5431d53d..00000000 --- a/src/xml/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -add_library(CruXml - XmlNode.cpp - XmlParser.cpp -) -target_compile_definitions(CruXml PRIVATE CRU_XML_EXPORT_API) -target_link_libraries(CruXml PUBLIC CruBase) diff --git a/src/xml/XmlNode.cpp b/src/xml/XmlNode.cpp deleted file mode 100644 index c9b73c50..00000000 --- a/src/xml/XmlNode.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "cru/xml/XmlNode.h" -#include - -namespace cru::xml { - -XmlElementNode* XmlNode::AsElement() { - return static_cast(this); -} - -XmlTextNode* XmlNode::AsText() { return static_cast(this); } - -XmlCommentNode* XmlNode::AsComment() { - return static_cast(this); -} - -const XmlElementNode* XmlNode::AsElement() const { - return static_cast(this); -} - -const XmlTextNode* XmlNode::AsText() const { - return static_cast(this); -} - -const XmlCommentNode* XmlNode::AsComment() const { - return static_cast(this); -} - -XmlElementNode::~XmlElementNode() { - for (auto child : children_) { - delete child; - } -} - -void XmlElementNode::AddAttribute(std::string key, std::string value) { - attributes_[std::move(key)] = std::move(value); -} - -void XmlElementNode::AddChild(XmlNode* child) { - Expects(child->GetParent() == nullptr); - children_.push_back(child); - child->parent_ = this; -} - -Index XmlElementNode::GetChildElementCount() const { - return std::count_if( - children_.cbegin(), children_.cend(), - [](xml::XmlNode* node) { return node->IsElementNode(); }); -} - -XmlElementNode* XmlElementNode::GetFirstChildElement() const { - for (auto child : children_) { - if (child->GetType() == XmlNode::Type::Element) { - return child->AsElement(); - } - } - return nullptr; -} - -XmlNode* XmlElementNode::Clone() const { - XmlElementNode* node = new XmlElementNode(tag_, attributes_); - - for (auto child : children_) { - node->AddChild(child->Clone()); - } - - return node; -} - -XmlCommentNode::~XmlCommentNode() {} - -XmlNode* XmlCommentNode::Clone() const { - XmlCommentNode* node = new XmlCommentNode(text_); - - return node; -} -} // namespace cru::xml diff --git a/src/xml/XmlParser.cpp b/src/xml/XmlParser.cpp deleted file mode 100644 index 9bfd5441..00000000 --- a/src/xml/XmlParser.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include "cru/xml/XmlParser.h" -#include "cru/base/StringUtil.h" -#include "cru/xml/XmlNode.h" - -namespace cru::xml { -XmlParser::XmlParser(std::string xml) : xml_(std::move(xml)) {} - -XmlParser::~XmlParser() { delete pseudo_root_node_; } - -XmlElementNode* XmlParser::Parse() { - if (!cache_) { - cache_ = DoParse(); - } - return static_cast(cache_->Clone()); -} - -char16_t XmlParser::Read1() { - if (current_position_ >= xml_.size()) { - throw XmlParsingException("Unexpected end of xml"); - } - return xml_[current_position_++]; -} - -std::string XmlParser::ReadWithoutAdvance(int count) { - if (current_position_ + count > xml_.size()) { - count = xml_.size() - current_position_; - } - return xml_.substr(current_position_, count); -} - -void XmlParser::ReadSpacesAndDiscard() { - while (current_position_ < xml_.size() && - (xml_[current_position_] == ' ' || xml_[current_position_] == '\t' || - xml_[current_position_] == '\n' || xml_[current_position_] == '\r')) { - ++current_position_; - } -} - -std::string XmlParser::ReadSpaces() { - std::string spaces; - while (current_position_ < xml_.size() && - (xml_[current_position_] == ' ' || xml_[current_position_] == '\t' || - xml_[current_position_] == '\n' || xml_[current_position_] == '\r')) { - spaces += xml_[current_position_]; - ++current_position_; - } - return spaces; -} - -std::string XmlParser::ReadIdenitifier() { - std::string identifier; - while (current_position_ < xml_.size() && - (xml_[current_position_] >= 'a' && xml_[current_position_] <= 'z' || - xml_[current_position_] >= 'A' && xml_[current_position_] <= 'Z' || - xml_[current_position_] >= '0' && xml_[current_position_] <= '9' || - xml_[current_position_] == '_')) { - identifier += xml_[current_position_]; - ++current_position_; - } - return identifier; -} - -std::string XmlParser::ReadAttributeString() { - if (Read1() != '"') { - throw XmlParsingException("Expected \"."); - } - - std::string string; - - while (true) { - char16_t c = Read1(); - - if (c == '"') { - break; - } - - string += c; - } - - return string; -} - -XmlElementNode* XmlParser::DoParse() { - while (current_position_ < xml_.size()) { - ReadSpacesAndDiscard(); - - if (current_position_ == xml_.size()) { - break; - } - - if (ReadWithoutAdvance() == "<") { - current_position_ += 1; - - if (ReadWithoutAdvance() == "/") { - current_position_ += 1; - - ReadSpacesAndDiscard(); - - std::string tag = ReadIdenitifier(); - - if (tag != current_->GetTag()) { - throw XmlParsingException("Tag mismatch."); - } - - ReadSpacesAndDiscard(); - - if (Read1() != '>') { - throw XmlParsingException("Expected >."); - } - - current_ = current_->GetParent(); - } else if (ReadWithoutAdvance(3) == "!--") { - current_position_ += 3; - - std::string text; - while (true) { - auto str = ReadWithoutAdvance(3); - if (str == "-->") break; - if (str.empty()) throw XmlParsingException("Unexpected end of xml"); - text += Read1(); - } - - current_position_ += 3; - current_->AddChild(new XmlCommentNode(cru::string::Trim(text))); - } else { - ReadSpacesAndDiscard(); - - std::string tag = ReadIdenitifier(); - - XmlElementNode* node = new XmlElementNode(tag); - - bool is_self_closing = false; - - while (true) { - ReadSpacesAndDiscard(); - auto c = ReadWithoutAdvance(); - if (c == ">") { - current_position_ += 1; - break; - } else if (c == "/") { - current_position_ += 1; - - if (Read1() != '>') { - throw XmlParsingException("Expected >."); - } - - is_self_closing = true; - break; - } else { - std::string attribute_name = ReadIdenitifier(); - - ReadSpacesAndDiscard(); - - if (Read1() != '=') { - throw XmlParsingException("Expected '='"); - } - - ReadSpacesAndDiscard(); - - std::string attribute_value = ReadAttributeString(); - - node->AddAttribute(attribute_name, attribute_value); - } - } - - current_->AddChild(node); - - if (!is_self_closing) { - current_ = node; - } - } - - } else { - std::string text; - - while (ReadWithoutAdvance() != "<") { - char16_t c = Read1(); - - text += c; - } - - if (!text.empty()) current_->AddChild(new XmlTextNode(cru::string::TrimEnd(text))); - } - } - - if (current_ != pseudo_root_node_) { - throw XmlParsingException("Unexpected end of xml"); - } - - if (pseudo_root_node_->GetChildren().size() != 1) { - throw XmlParsingException("Expected 1 node as root."); - } - - return static_cast(pseudo_root_node_->GetChildren()[0]); -} -} // namespace cru::xml -- cgit v1.2.3