diff --git a/docs/examples.md b/docs/examples.md index ffb0d0a..02d8f3c 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -61,6 +61,19 @@ std::vector children = root.elems(); std::vector children = root.elems("child"); ``` +#### Insertion + +```C++ +using namespace myxml; +element root("root"); +element child("child"); +root.push_back(child); +REQUIRE(root.first_elem().name() == "child"); +element next("next"); +root.push_front(next); +REQUIRE(root.first_elem().name() == "next"); +``` + ### Text ```C++ diff --git a/include/myxml/element.hpp b/include/myxml/element.hpp index c49a72a..67bf618 100644 --- a/include/myxml/element.hpp +++ b/include/myxml/element.hpp @@ -3,14 +3,42 @@ #include #include #include +#include #include "myxml/text.hpp" #include "myxml/cdata.hpp" #include "myxml/printable.hpp" +#include "myxml/interface.hpp" namespace myxml { + struct element_impl : public composite_node // public std::enable_shared_from_this, public Node + { + public: + std::string _name; + std::map> _attributes; + + /* Set initializer as private to avoid using Element without share_ptr*/ + + virtual ~element_impl() = default; + explicit element_impl(std::string_view name); + element_impl() = default; + /* Builder */ + // Wraps creating shared_ptr + static std::shared_ptr _new(std::string_view name); + static std::shared_ptr _new(); + static std::shared_ptr parse(std::string_view buf); + static std::shared_ptr load(std::string_view path); + + /* Manipulate */ + void extend_attributes(std::map); + std::string &operator[](const std::string &); + + /* Implement Exportable */ + virtual void print(std::ostream &) const override; + }; + enum class ClosingType { Closed, @@ -25,7 +53,7 @@ namespace myxml element operator""_elem(const char *, std::size_t); } - class element : public printable + class element : public printable, public interface { friend element literals::operator""_elem(const char *, std::size_t); @@ -44,40 +72,31 @@ namespace myxml std::string &operator[](const std::string &); std::string_view name(); + /* Query */ element first_elem(); element first_elem(std::string_view); text first_text(); cdata first_cdata(); + /* Manipulate */ + template >> + void push_back(T child) + { + _impl->push_back(child.impl()); + } + + template >> + void push_front(T child) + { + _impl->push_front(child.impl()); + } + /* Implement printable */ virtual void print(std::ostream &) const override; virtual void entity_encoding(bool) override; virtual void platform_specific_newline(bool) override; - }; - - struct element_impl : public composite_node // public std::enable_shared_from_this, public Node - { - public: - std::string _name; - std::map> _attributes; - - /* Set initializer as private to avoid using Element without share_ptr*/ - - virtual ~element_impl() = default; - explicit element_impl(std::string_view name); - element_impl() = default; - /* Builder */ - // Wraps creating shared_ptr - static std::shared_ptr _new(std::string_view name); - static std::shared_ptr _new(); - static std::shared_ptr parse(std::string_view buf); - static std::shared_ptr load(std::string_view path); - /* Manipulate */ - void extend_attributes(std::map); - std::string &operator[](const std::string &); - - /* Implement Exportable */ - virtual void print(std::ostream &) const override; + /* Implement interface*/ + virtual std::shared_ptr impl() { return _impl; } }; } diff --git a/include/myxml/interface.hpp b/include/myxml/interface.hpp new file mode 100644 index 0000000..2365255 --- /dev/null +++ b/include/myxml/interface.hpp @@ -0,0 +1,14 @@ +#pragma once +#include +#include "myxml/node.hpp" + +namespace myxml +{ + // contains an _impl + // e.g. element, text, cdata + class interface + { + public: + virtual std::shared_ptr impl() = 0; + }; +} \ No newline at end of file diff --git a/src/element.cpp b/src/element.cpp index 5bfacbc..e8a2119 100644 --- a/src/element.cpp +++ b/src/element.cpp @@ -104,28 +104,6 @@ namespace myxml return this->_attributes[key]; } - // std::string element_impl::ExportRaw() const - // { - - // std::string builder = "<" + std::string(this->name); - // for (const auto &[key, value] : this->attributes) - // { - // builder += "" + key + "=\"" + value + "\""; - // } - // if (this->FirstChild() == nullptr) - // { - // builder += " />"; - // return builder; - // } - // builder += ">"; - // for (auto node = this->FirstChild(); node != nullptr; node = node->NextSibiling()) - // { - // builder += node->ExportRaw(); - // } - // builder += "name) + ">"; - // return builder; - // } - void element_impl::print(std::ostream &os) const { os << "<" << this->_name; diff --git a/tests/element_test.cpp b/tests/element_test.cpp index b0c7e2d..c85393b 100644 --- a/tests/element_test.cpp +++ b/tests/element_test.cpp @@ -49,7 +49,37 @@ TEST_CASE("Element Impl", "[element]") } } -TEST_CASE("Custom String Literal", "[Element]") +TEST_CASE("Element Interface", "[element]") +{ + using namespace myxml; + using namespace myxml::literals; + + element root("root"); + element child("child"); + + SECTION("element::name") + { + REQUIRE(root.name() == "root"); + } + + SECTION("insertion") + { + + root.push_back(child); + REQUIRE(root.first_elem().name() == "child"); + element next("next"); + root.push_front(next); + REQUIRE(root.first_elem().name() == "next"); + } + + SECTION("query by name") + { + root.push_back(child); + REQUIRE(root.first_elem("child").name() == "child"); + } +} + +TEST_CASE("Custom String Literal", "[element]") { using namespace myxml::literals; auto elem = ""_elem;