#pragma once #include #include #include #include #include #include "commons.hpp" namespace xml { class Node; class Attribute; class Document; class Attribute { std::string name; std::string text; public: Attribute() = default; Attribute(std::string name, std::string text); const std::string& getName() const; const std::string& getText() const; int64_t asInt() const; double asFloat() const; bool asBool() const; glm::vec2 asVec2() const; glm::vec3 asVec3() const; glm::vec4 asVec4() const; glm::vec4 asColor() const; }; /// @brief XML element class. Text element has tag 'text' and attribute /// 'text' class Node { std::string tag; std::unordered_map attrs; std::vector> elements; public: Node(std::string tag); Node(const Node&) = delete; /// @brief Add sub-element void add(std::unique_ptr element); /// @brief Set attribute value. Creates attribute if does not exists /// @param name attribute name /// @param text attribute value void set(const std::string& name, const std::string& text); /// @brief Get element tag const std::string& getTag() const; bool isText() const { return getTag() == "#"; } const std::string& getInnerText() const { return attr("#").getText(); } /// @brief Get attribute by name /// @param name attribute name /// @throws std::runtime_error if element has no attribute /// @return xml attribute - {name, value} const Attribute& attr(const std::string& name) const; /// @brief Get attribute by name /// @param name attribute name /// @param def default value will be returned wrapped in xmlattribute /// if element has no attribute /// @return xml attribute - {name, value} or {name, def} if not found Attribute attr(const std::string& name, const std::string& def) const; /// @brief Check if element has attribute /// @param name attribute name bool has(const std::string& name) const; /// @brief Get sub-element by index /// @param index sub-element index /// @throws std::out_of_range if an invalid index given /// @return sub-element Node& sub(size_t index); const Node& sub(size_t index) const; /// @brief Get number of sub-elements size_t size() const; const std::vector>& getElements() const; const std::unordered_map& getAttributes() const; }; class Document { std::unique_ptr root = nullptr; std::string version; std::string encoding; public: Document(std::string version, std::string encoding); void setRoot(std::unique_ptr element); const Node* getRoot() const; const std::string& getVersion() const; const std::string& getEncoding() const; }; /// @brief Serialize XML Document to string /// @param document serializing document /// @param nice use human readable format (with indents and line-separators) /// @param indentStr indentation characters sequence (default - 4 spaces) /// @return XML string std::string stringify( const Document& document, bool nice = true, const std::string& indentStr = " " ); /// @brief Read XML Document from string /// @param filename file name will be shown in error messages /// @param source xml source code string /// @return xml document std::unique_ptr parse( std::string_view filename, std::string_view source ); std::unique_ptr parse_vcm( std::string_view filename, std::string_view source, std::string_view tag ); using xmlelement = Node; }