diff --git a/README.md b/README.md
index 28ec653..1b9a41a 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,19 @@
Small C++ library for generating XML, HTML and CSS.
+## Features
+
+- HTML, CSS and XML document generation and deserialization
+- Sensible indentation for pretty-formatting.
+- Modern C++ API
+- No dependencies, other than the standard library
+- Windows, macOS, Linux and *BSD support
+- LGPL license
+
+## Not yet implemented
+
+- HTML/XML/CSS serialization (parsing from e.g. file)
+
## Installation
To install the library, you can utilize the provided CMakeLists.txt file:
diff --git a/examples/hello-world.cpp b/examples/hello-world.cpp
index 7844e18..d4464b3 100644
--- a/examples/hello-world.cpp
+++ b/examples/hello-world.cpp
@@ -82,12 +82,18 @@ int main() {
headSection.push_back(docpp::HTML::HTMLElement("style", {}, css)); //
- /* Add a paragraph element to the body section. */
- bodySection.push_back(docpp::HTML::HTMLElement("p", {}, "Hello, world!")); //
Hello, world!
-
- /* Likewise, add a paragraph element to the footer section. */
+ /* Add a paragraph element to the footer section. */
footerSection.push_back(docpp::HTML::HTMLElement("p", {}, "This is the footer.")); // This is the footer.
+ docpp::HTML::HTMLSection divSection(docpp::HTML::SECTION_DIV, {{docpp::HTML::HTMLProperty("id", "main")}}); //
+
+ /* Add a header element and a paragraph element to the div section. */
+ divSection.push_back(docpp::HTML::HTMLElement("h1", {}, "Hello world!")); // Hello world!
+ divSection.push_back(docpp::HTML::HTMLElement("p", {}, "This is a paragraph.")); // This is a paragraph.
+
+ /* Add the div section to the body section. */
+ bodySection.push_back(divSection);
+
/* Now, let's add the header, body and footer section to the html section.
* The order does matter, because an identifier is used internally. You can get this identifier by e.g. using find().
*/
@@ -102,7 +108,7 @@ int main() {
std::ofstream file("hello-world.html");
/* Optionally, you can use the get() method with the docpp::HTML::FORMATTING_PRETTY argument to get a *slightly* more readable document.
- * It still doesn't look hand-made, but it's readable at least. The same goes for the CSS document.
+ * The same goes for the CSS document. Or, you can use docpp::HTML::FORMATTING_NEWLINE to get a document with elements separated by newlines.
*/
file << doc.get(docpp::HTML::FORMATTING_PRETTY);
diff --git a/include/docpp.hpp b/include/docpp.hpp
index 6f08926..42dd3b2 100644
--- a/include/docpp.hpp
+++ b/include/docpp.hpp
@@ -33,6 +33,7 @@ namespace docpp {
TYPE_NON_CLOSED,
FORMATTING_NONE,
FORMATTING_PRETTY,
+ FORMATTING_NEWLINE,
};
/**
@@ -231,7 +232,7 @@ namespace docpp {
* @brief Get the element in the form of an HTML tag.
* @return std::string The tag of the element
*/
- std::string get(const int formatting = FORMATTING_NONE) const;
+ std::string get(const int formatting = FORMATTING_NONE, const int tabc = 0) const;
/**
* @brief Get the tag of the element
@@ -412,7 +413,7 @@ namespace docpp {
* @brief Dump the entire section.
* @return std::string The section
*/
- std::string get(const int formatting = FORMATTING_NONE) const;
+ std::string get(const int formatting = FORMATTING_NONE, const int tabc = 0) const;
HTMLSection operator=(const HTMLSection& section);
void operator+=(const HTMLElement& element);
@@ -439,7 +440,7 @@ namespace docpp {
* @param std::string The type to return
* @return std::string The document
*/
- std::string get(const int formatting = FORMATTING_NONE) const;
+ std::string get(const int formatting = FORMATTING_NONE, const int tabc = 0) const;
/**
* @brief Get the section
@@ -482,6 +483,7 @@ namespace docpp {
enum {
FORMATTING_NONE,
FORMATTING_PRETTY,
+ FORMATTING_NEWLINE,
};
class CSSProperty {
@@ -641,7 +643,7 @@ namespace docpp {
* @brief Get the element
* @return std::pair> The element
*/
- std::string get(const int formatting = FORMATTING_NONE) const;
+ std::string get(const int formatting = FORMATTING_NONE, const int tabc = 0) const;
/**
* @brief Get the tag of the element
* @return std::string The tag of the element
@@ -749,7 +751,7 @@ namespace docpp {
* @brief Get the stylesheet
* @return std::string The stylesheet
*/
- std::string get(const int formatting = FORMATTING_NONE) const;
+ std::string get(const int formatting = FORMATTING_NONE, const int tabc = 0) const;
CSSStylesheet operator=(const CSSStylesheet& stylesheet);
void operator+=(const CSSElement& element);
diff --git a/src/docpp.cpp b/src/docpp.cpp
index b66b223..15f3eb0 100644
--- a/src/docpp.cpp
+++ b/src/docpp.cpp
@@ -184,9 +184,15 @@ void docpp::HTML::HTMLElement::set(const std::string& tag, const HTMLElementProp
this->type = type;
}
-std::string docpp::HTML::HTMLElement::get(const int formatting) const {
+std::string docpp::HTML::HTMLElement::get(const int formatting, const int tabc) const {
std::string ret{};
+ if (formatting == docpp::HTML::FORMATTING_PRETTY) {
+ for (int i{0}; i < tabc; i++) {
+ ret += "\t";
+ }
+ }
+
ret += "<" + this->tag;
for (const auto& it : this->properties.getProperties()) {
@@ -206,7 +212,7 @@ std::string docpp::HTML::HTMLElement::get(const int formatting) const {
ret += this->data + "/>";
}
- if (formatting == docpp::HTML::FORMATTING_PRETTY) {
+ if (formatting == docpp::HTML::FORMATTING_PRETTY || formatting == docpp::HTML::FORMATTING_NEWLINE) {
ret += "\n";
}
@@ -456,9 +462,15 @@ std::vector docpp::HTML::HTMLSection::getHTMLSections(
return std::move(ret);
}
-std::string docpp::HTML::HTMLSection::get(const int formatting) const {
+std::string docpp::HTML::HTMLSection::get(const int formatting, const int tabc) const {
std::string ret{};
+ if (formatting == docpp::HTML::FORMATTING_PRETTY) {
+ for (int i{0}; i < tabc; i++) {
+ ret += "\t";
+ }
+ }
+
ret += "<" + this->tag;
for (const auto& it : this->properties.getProperties()) {
@@ -470,22 +482,28 @@ std::string docpp::HTML::HTMLSection::get(const int formatting) const {
ret += ">";
- if (formatting == docpp::HTML::FORMATTING_PRETTY) {
+ if (formatting == docpp::HTML::FORMATTING_PRETTY || formatting == docpp::HTML::FORMATTING_NEWLINE) {
ret += "\n";
}
for (int i{0}; i < this->index; i++) {
if (this->elements.find(i) != this->elements.end()) {
- ret += this->elements.at(i).get(formatting);
+ ret += this->elements.at(i).get(formatting, tabc + 1);
} else if (this->sections.find(i) != this->sections.end()) {
- ret += this->sections.at(i).get(formatting);
+ ret += this->sections.at(i).get(formatting, tabc + 1);
- if (formatting == docpp::HTML::FORMATTING_PRETTY) {
+ if (formatting == docpp::HTML::FORMATTING_PRETTY || formatting == docpp::HTML::FORMATTING_NEWLINE) {
ret += "\n";
}
}
}
+ if (formatting == docpp::HTML::FORMATTING_PRETTY) {
+ for (int i{0}; i < tabc; i++) {
+ ret += "\t";
+ }
+ }
+
ret += "" + this->tag + ">";
return std::move(ret);
@@ -509,8 +527,8 @@ void docpp::HTML::HTMLSection::swap(const HTMLSection& section1, const HTMLSecti
this->swap(this->find(section1), this->find(section2));
}
-std::string docpp::HTML::HTMLDocument::get(const int formatting) const {
- return this->doctype + (formatting == FORMATTING_PRETTY ? "\n" : "") + this->document.get(formatting);
+std::string docpp::HTML::HTMLDocument::get(const int formatting, const int tabc) const {
+ return this->doctype + (formatting == FORMATTING_PRETTY ? "\n" : formatting == FORMATTING_NEWLINE ? "\n" : "") + this->document.get(formatting, tabc);
}
docpp::HTML::HTMLSection& docpp::HTML::HTMLDocument::getSection() {
@@ -689,13 +707,13 @@ void docpp::CSS::CSSElement::swap(const CSSProperty& property1, const CSSPropert
this->swap(this->find(property1), this->find(property2));
}
-std::string docpp::CSS::CSSElement::get(const int formatting) const {
+std::string docpp::CSS::CSSElement::get(const int formatting, const int tabc) const {
std::string ret{};
if (this->element.first.compare("")) {
ret += this->element.first + " {";
- if (formatting == docpp::CSS::FORMATTING_PRETTY) {
+ if (formatting == docpp::CSS::FORMATTING_PRETTY || formatting == docpp::CSS::FORMATTING_NEWLINE) {
ret += "\n";
}
@@ -703,16 +721,22 @@ std::string docpp::CSS::CSSElement::get(const int formatting) const {
if (!it.getKey().compare("")) continue;
if (!it.getValue().compare("")) continue;
+ if (formatting == docpp::CSS::FORMATTING_PRETTY) {
+ for (int i{0}; i < tabc + 1; i++) {
+ ret += "\t";
+ }
+ }
+
ret += it.getKey() + ": " + it.getValue() + ";";
- if (formatting == docpp::CSS::FORMATTING_PRETTY) {
+ if (formatting == docpp::CSS::FORMATTING_PRETTY || formatting == docpp::CSS::FORMATTING_NEWLINE) {
ret += "\n";
}
}
ret += "}";
- if (formatting == docpp::CSS::FORMATTING_PRETTY) {
+ if (formatting == docpp::CSS::FORMATTING_PRETTY || formatting == docpp::CSS::FORMATTING_NEWLINE) {
ret += "\n";
}
}
@@ -821,11 +845,11 @@ std::vector docpp::CSS::CSSStylesheet::getElements() con
return this->elements;
}
-std::string docpp::CSS::CSSStylesheet::get(const int formatting) const {
+std::string docpp::CSS::CSSStylesheet::get(const int formatting, const int tabc) const {
std::string ret{};
for (const auto& it : this->elements) {
- ret += it.get(formatting);
+ ret += it.get(formatting, tabc);
}
return std::move(ret);
diff --git a/tests/test.cpp b/tests/test.cpp
index 233aa29..1d87b14 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -41,7 +41,7 @@ SCENARIO("Test HTML", "[HTML]") {
const std::string expected_html{"Test TitleTest Header
Test Paragraph
Test Paragraph With ID
Test Paragraph With ID And Class
"};
REQUIRE(doc.get() == expected_html);
- REQUIRE(doc.get(docpp::HTML::FORMATTING_PRETTY) == "\n\n\nTest Title\n\n\nTest Header
\nTest Paragraph
\nTest Paragraph With ID
\n\n
Test Paragraph In Div
\n
\nTest Paragraph With ID And Class
\n\n\n");
+ REQUIRE(doc.get(docpp::HTML::FORMATTING_NEWLINE) == "\n\n\nTest Title\n\n\nTest Header
\nTest Paragraph
\nTest Paragraph With ID
\n\n
Test Paragraph In Div
\n
\nTest Paragraph With ID And Class
\n\n\n");
};
auto test2 = []() {
@@ -54,7 +54,7 @@ SCENARIO("Test HTML", "[HTML]") {
section.erase(docpp::HTML::HTMLElement("p", {}, "Test 2"));
REQUIRE(section.get() == "Test 1
Test 3
");
- REQUIRE(section.get(docpp::HTML::FORMATTING_PRETTY) == "\nTest 1
\nTest 3
\n");
+ REQUIRE(section.get(docpp::HTML::FORMATTING_NEWLINE) == "\nTest 1
\nTest 3
\n");
};
auto test3 = []() {
@@ -68,7 +68,7 @@ SCENARIO("Test HTML", "[HTML]") {
section.insert(pos, docpp::HTML::HTMLElement("p", {}, "Test 2.5"));
REQUIRE(section.get() == "Test 1
Test 2.5
Test 3
");
- REQUIRE(section.get(docpp::HTML::FORMATTING_PRETTY) == "\nTest 1
\nTest 2.5
\nTest 3
\n");
+ REQUIRE(section.get(docpp::HTML::FORMATTING_NEWLINE) == "\nTest 1
\nTest 2.5
\nTest 3
\n");
};
auto test4 = []() {
@@ -83,7 +83,7 @@ SCENARIO("Test HTML", "[HTML]") {
section.erase(pos);
REQUIRE(section.get() == "Test 1
Test 3
");
- REQUIRE(section.get(docpp::HTML::FORMATTING_PRETTY) == "\nTest 1
\nTest 3
\n");
+ REQUIRE(section.get(docpp::HTML::FORMATTING_NEWLINE) == "\nTest 1
\nTest 3
\n");
};
auto test5 = []() {
@@ -103,7 +103,7 @@ SCENARIO("Test HTML", "[HTML]") {
doc.set(section);
REQUIRE(doc.get() == "");
- REQUIRE(doc.get(docpp::HTML::FORMATTING_PRETTY) == "\n\n\n");
+ REQUIRE(doc.get(docpp::HTML::FORMATTING_NEWLINE) == "\n\n\n");
};
auto test6 = []() {
@@ -113,7 +113,7 @@ SCENARIO("Test HTML", "[HTML]") {
css.push_back(element);
REQUIRE(css.get() == "p {color: red;font-size: 16px;font-family: Arial;}");
- REQUIRE(css.get(docpp::CSS::FORMATTING_PRETTY) == "p {\ncolor: red;\nfont-size: 16px;\nfont-family: Arial;\n}\n");
+ REQUIRE(css.get(docpp::CSS::FORMATTING_NEWLINE) == "p {\ncolor: red;\nfont-size: 16px;\nfont-family: Arial;\n}\n");
};
auto test7 = []() {
@@ -284,6 +284,18 @@ SCENARIO("Test HTML", "[HTML]") {
REQUIRE(doc.get() == "Test 4
Test 5
Test 6
Test 7
");
};
+ auto test17 = []() {
+ docpp::HTML::HTMLSection section = docpp::HTML::HTMLSection(docpp::HTML::SECTION_HTML, {});
+
+ section.push_back(docpp::HTML::HTMLElement("p", {}, "Test 1"));
+ section.push_back(docpp::HTML::HTMLElement("p", {}, "Test 2"));
+ section.push_back(docpp::HTML::HTMLElement("p", {}, "Test 3"));
+
+ docpp::HTML::HTMLDocument doc{section};
+
+ REQUIRE(doc.get(docpp::HTML::FORMATTING_PRETTY) == "\n\n\tTest 1
\n\tTest 2
\n\tTest 3
\n");
+ };
+
std::vector tests{
test1,
test2,
@@ -301,6 +313,7 @@ SCENARIO("Test HTML", "[HTML]") {
test14,
test15,
test16,
+ test17,
};
for (const auto& test : tests) {