diff --git a/docs/examples.md b/docs/examples.md index 02d8f3c..c635b26 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -72,6 +72,8 @@ REQUIRE(root.first_elem().name() == "child"); element next("next"); root.push_front(next); REQUIRE(root.first_elem().name() == "next"); +root.push_back(text("Hello")); +REQUIRE(root.first_text().str() == "Hello"); ``` ### Text @@ -84,10 +86,10 @@ text txt = "Hello"; text txt = root.first_text(); // print raw fmt::println(txt); -// print trimmed text, it returns std::string and will not modify it -fmt::println(txt.trimmed()); -// yet it will modify. return a new text +// print trimmed string, it returns std::string and will not modify it fmt::println(txt.trim()); +// return a new trimmed text +fmt::println(txt.trimmed()); ``` ### CData diff --git a/include/myxml/text.hpp b/include/myxml/text.hpp index 0c79ef2..3f4c712 100644 --- a/include/myxml/text.hpp +++ b/include/myxml/text.hpp @@ -1,11 +1,25 @@ #pragma once #include #include "myxml/node.hpp" +#include "myxml/interface.hpp" namespace myxml { - class text : public printable + struct text_impl : public node + { + std::string inner; + + text_impl() = default; + explicit text_impl(std::string_view str); + + virtual ~text_impl() = default; + + /* Implment Exportable*/ + virtual void print(std::ostream &) const override; + }; + + class text : public printable, public interface { friend class element; @@ -15,26 +29,19 @@ namespace myxml text(std::shared_ptr); public: - text(std::string_view); + text(const std::string &); text(std::string &&); + std::string trimmed(); + text trim(); + /* Implement printable */ virtual void print(std::ostream &) const override; virtual void entity_encoding(bool) override; virtual void platform_specific_newline(bool) override; - }; - struct text_impl : public node - { - std::string inner; - - text_impl() = default; - explicit text_impl(std::string_view str); - - virtual ~text_impl() = default; - - /* Implment Exportable*/ - virtual void print(std::ostream &) const override; + /* Implement interface */ + virtual std::shared_ptr impl() { return _impl; } }; namespace util diff --git a/src/text.cpp b/src/text.cpp index f053e26..8138480 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -15,12 +15,28 @@ namespace myxml _impl->inner = str; } - text::text(std::string_view str) + text::text(const std::string &str) { _impl = std::make_shared(); _impl->inner = str; } + std::string text::trimmed() + { + std::string trimmed; + auto is_space = [](char ch) + { return std::isspace(static_cast(ch)); }; + auto &ref = _impl->inner; + auto start = std::find_if_not(ref.begin(), ref.end(), is_space); + auto end = std::find_if_not(ref.rbegin(), ref.rend(), is_space).base(); + return (start < end) ? std::string(start, end) : std::string(); + } + + text text::trim() + { + return this->trimmed(); + } + void text::print(std::ostream &os) const { this->_impl->print(os); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c894429..65da8e8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,3 +13,4 @@ add_custom_test(parser_test) add_custom_test(printable_test) add_custom_test(document_test) add_custom_test(buffer_test) +add_custom_test(text_test) diff --git a/tests/element_test.cpp b/tests/element_test.cpp index c85393b..1f2ffd2 100644 --- a/tests/element_test.cpp +++ b/tests/element_test.cpp @@ -70,6 +70,8 @@ TEST_CASE("Element Interface", "[element]") element next("next"); root.push_front(next); REQUIRE(root.first_elem().name() == "next"); + root.push_back(text("Hello")); + REQUIRE(root.first_text().str() == "Hello"); } SECTION("query by name") diff --git a/tests/text_test.cpp b/tests/text_test.cpp new file mode 100644 index 0000000..033ef6a --- /dev/null +++ b/tests/text_test.cpp @@ -0,0 +1,14 @@ +#include +#include "myxml/text.hpp" + +TEST_CASE("text interface", "[text]") +{ + using namespace myxml; + + SECTION("trim") + { + text text(" \n\n Hello \n \t "); + REQUIRE(text.trimmed() == "Hello"); + REQUIRE(text.trim().str() == "Hello"); + } +} \ No newline at end of file