hemplate

Simple XML template engine
git clone git://git.dimitrijedobrota.com/hemplate.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit d287efed0625b53751c1eb47d9a91d46a42c7218
parent 5dbbc906fba4ffb4aac3d9d2ca4b28529573ec48
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Wed, 23 Apr 2025 12:17:28 +0200

Improve element by inheriting from attribute_list

Diffstat:
M include/hemplate/element.hpp | ++++++++++++++++++++++++++++++++ -------------------------------
M source/attribute.cpp | + -
M source/element.cpp | +++++++++ -------------------------------------

3 files changed, 42 insertions(+), 69 deletions(-)


diff --git a/ include/hemplate/element.hpp b/ include/hemplate/element.hpp

@@ -16,7 +16,7 @@ class element;

template<typename T>
concept is_element = std::derived_from<T, element>;

class HEMPLATE_EXPORT element
class HEMPLATE_EXPORT element : public attribute_list
{
public:
enum class Type : uint8_t

@@ -28,90 +28,93 @@ public:

Transparent,
};

const attribute_list& attributes() const { return *this; }

private:
using attribute_list::empty;

template<based::string_literal Tag, element::Type MyType>
friend class element_builder;

bool* m_state;
Type m_type;
std::string m_name;
std::string m_tag;

attribute_list m_attributes;
std::vector<element> m_children;
std::string m_data;

explicit element(bool& state,
Type type,
std::string_view name,
std::string_view tag,
const is_element auto&... children)
: m_state(&state)
, m_type(type)
, m_name(name)
, m_tag(tag)
, m_children(std::initializer_list<element> {children...})
{
}

explicit element(bool& state,
Type type,
std::string_view name,
std::string_view tag,
std::string_view data)
: m_state(&state)
, m_type(type)
, m_name(name)
, m_tag(tag)
, m_data(data)
{
}

explicit element(bool& state,
Type type,
std::string_view name,
std::string_view tag,
std::span<const element> children)
: m_state(&state)
, m_type(type)
, m_name(name)
, m_tag(tag)
, m_children(children.begin(), children.end())
{
}

explicit element(bool& state,
Type type,
std::string_view name,
std::string_view tag,
attribute_list attributes,
const is_element auto&... children)
: m_state(&state)
: attribute_list(std::move(attributes))
, m_state(&state)
, m_type(type)
, m_name(name)
, m_attributes(std::move(attributes))
, m_tag(tag)
, m_children(std::initializer_list<element> {children...})
{
}

explicit element(bool& state,
Type type,
std::string_view name,
std::string_view tag,
attribute_list attributes,
std::string_view data)
: m_state(&state)
: attribute_list(std::move(attributes))
, m_state(&state)
, m_type(type)
, m_name(name)
, m_attributes(std::move(attributes))
, m_tag(tag)
, m_data(data)
{
}

explicit element(bool& state,
Type type,
std::string_view name,
std::string_view tag,
attribute_list attributes,
std::span<const element> children)
: m_state(&state)
: attribute_list(std::move(attributes))
, m_state(&state)
, m_type(type)
, m_name(name)
, m_attributes(std::move(attributes))
, m_tag(tag)
, m_children(children.begin(), children.end())
{
}

template<based::string_literal Tag, element::Type MyType>
friend class element_builder;

void render_atomic(std::ostream& out, std::size_t indent_value) const;
void render_boolean(std::ostream& out, std::size_t indent_value) const;
void render_comment(std::ostream& out, std::size_t indent_value) const;

@@ -126,13 +129,11 @@ public:

return out;
}

element& add(const element& elem);

element& set(const attribute_list& list);
element& set(attribute attr);

element add(const attribute_list& list) const;
element add(attribute attr) const;
element& add(const element& elem)
{
m_children.emplace_back(elem);
return *this;
}

bool get_state() const { return *m_state; }
bool tgl_state() const { return *m_state = !*m_state; }

diff --git a/ source/attribute.cpp b/ source/attribute.cpp

@@ -48,7 +48,7 @@ attribute_list& attribute_list::set(attribute attr)

if (attr.name == "class") {
m_class.append(" ", attr.value);
} else if (attr.name == "style") {
m_class.append("; ", attr.value);
m_style.append("; ", attr.value);
} else {
m_attributes.emplace_back(std::move(attr));
}

diff --git a/ source/element.cpp b/ source/element.cpp

@@ -7,12 +7,6 @@

namespace hemplate
{

element& element::add(const element& elem)
{
m_children.emplace_back(elem);
return *this;
}

void element::render_comment(std::ostream& out, std::size_t indent_value) const
{
const std::string indent(indent_value, ' ');

@@ -24,13 +18,13 @@ void element::render_atomic(std::ostream& out, std::size_t indent_value) const

{
const std::string indent(indent_value, ' ');

out << indent << std::format("<{} {}/>\n", m_name, m_attributes);
out << indent << std::format("<{} {}/>\n", m_tag, attributes());
}

void element::render_xml(std::ostream& out, std::size_t indent_value) const
{
const std::string indent(indent_value, ' ');
out << indent << std::format("<?xml {}?>\n", m_attributes);
out << indent << std::format("<?xml {}?>\n", attributes());
}

void element::render_children(std::ostream& out, std::size_t indent_value) const

@@ -61,13 +55,13 @@ void element::render(std::ostream& out, std::size_t indent_value) const

break;
}

if (m_name.empty()) {
if (m_tag.empty()) {
out << indent << m_data << '\n';
return;
}

if (!m_data.empty()) {
out << indent << std::format("<{} {}>\n", m_name, m_attributes);
out << indent << std::format("<{} {}>\n", m_tag, attributes());

if (!m_children.empty()) {
render_children(out, indent_value + 2);

@@ -75,43 +69,21 @@ void element::render(std::ostream& out, std::size_t indent_value) const

out << indent << " " << m_data << '\n';
}

out << indent << std::format("</{}>\n", m_name);
out << indent << std::format("</{}>\n", m_tag);
return;
}

if (m_children.empty()) {
if (tgl_state()) {
out << indent << std::format("<{} {}>\n", m_name, m_attributes);
out << indent << std::format("<{} {}>\n", m_tag, attributes());
} else {
out << indent << std::format("</{}>\n", m_name);
out << indent << std::format("</{}>\n", m_tag);
}
} else {
out << indent << std::format("<{} {}>\n", m_name, m_attributes);
out << indent << std::format("<{} {}>\n", m_tag, attributes());
render_children(out, indent_value + 2);
out << indent << std::format("</{}>\n", m_name);
out << indent << std::format("</{}>\n", m_tag);
}
}

element& element::set(const attribute_list& list)
{
m_attributes.set(list);
return *this;
}

element& element::set(attribute attr)
{
m_attributes.set(std::move(attr));
return *this;
}

element element::add(const attribute_list& list) const
{
return element(*this).set(list);
}

element element::add(attribute attr) const
{
return element(*this).set(std::move(attr));
}

} // namespace hemplate