1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
// Copyright Maarten L. Hekkelman, 2019
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
/// \file
/// definition of the zeep::http::tag_processor classes. These classes take care of processing HTML templates
#include <zeep/config.hpp>
#include <filesystem>
#include <zeep/xml/document.hpp>
#include <zeep/http/el-processing.hpp>
namespace zeep::http
{
class html_controller;
class basic_template_processor;
// --------------------------------------------------------------------
//
/// \brief Abstract base class for tag_processor.
///
/// Note that this class should be light in construction, we create it every time a page is rendered.
class tag_processor
{
public:
tag_processor(const tag_processor&) = delete;
tag_processor& operator=(const tag_processor&) = delete;
virtual ~tag_processor() = default;
/// \brief process xml parses the XHTML and fills in the special tags and evaluates the el constructs
///
/// This function is called to modify the xml tree in \a node
///
/// \param node The XML zeep::xml::node (element) to manipulate
/// \param scope The zeep::http::scope containing the variables and request
/// \param dir The path to the docroot, the directory containing the XHTML templates
/// \param webapp The instance of webapp that called this function
virtual void process_xml(xml::node* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader) = 0;
protected:
/// \brief constructor
///
/// \param ns Then XML namespace for the tags and attributes that are processed by this tag_processor
tag_processor(const char* ns)
: m_ns(ns) {}
std::string m_ns;
};
// --------------------------------------------------------------------
/// \brief A tag_processor compatible with the old version of libzeep. Works
/// on tags only, not on attributes. Also parses any occurrence of ${}.
/// For newer code, please consider using the v2 version only.
class tag_processor_v1 : public tag_processor
{
public:
/// \brief default namespace for this processor
static constexpr const char* ns() { return "http://www.hekkelman.com/libzeep/m1"; }
/// \brief constructor
///
/// By default the namespace for the v1 processor is the one in ns()
tag_processor_v1(const char* ns = tag_processor_v1::ns());
/// \brief actual implementation of the tag processing.
virtual void process_xml(xml::node* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
protected:
virtual void process_tag(const std::string& tag, xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
private:
/// handler for mrs:include tags
void process_include(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_if(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_iterate(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_for(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_number(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_options(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_option(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_checkbox(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_url(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_param(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_embed(xml::element* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
bool process_el(const scope& scope, std::string& s);
};
// --------------------------------------------------------------------
/// \brief version two of the tag_processor in libzeep
///
/// This is the new tag_processor. It is designed to look a bit like
/// Thymeleaf (https://www.thymeleaf.org/)
/// This processor works on attributes mostly, but can process inline
/// el constructs as well.
///
/// The documentention contains a section describing all the
/// xml tags and attributes this processor handles.
class tag_processor_v2 : public tag_processor
{
public:
/// \brief default namespace for this processor
static constexpr const char* ns() { return "http://www.hekkelman.com/libzeep/m2"; }
/// \brief each handler returns a code telling the processor what to do with the node
enum class AttributeAction
{
none, remove, replace
};
using attr_handler = std::function<AttributeAction(xml::element*, xml::attribute*, scope&, std::filesystem::path, basic_template_processor& loader)>;
/// \brief constructor with default namespace
tag_processor_v2(const char* ns = tag_processor_v2::ns());
/// \brief process xml parses the XHTML and fills in the special tags and evaluates the el constructs
virtual void process_xml(xml::node* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
/// \brief It is possible to extend this processor with custom handlers
void register_attr_handler(const std::string& attr, attr_handler&& handler)
{
m_attr_handlers.emplace(attr, std::forward<attr_handler>(handler));
}
protected:
void process_node(xml::node* node, const scope& scope, std::filesystem::path dir, basic_template_processor& loader);
void process_text(xml::text& t, const scope& scope);
void post_process(xml::element* e, const scope& parentScope, std::filesystem::path dir, basic_template_processor& loader);
// std::vector<std::unique_ptr<xml::node>> resolve_fragment_spec(xml::element* node, std::filesystem::path dir, basic_html_controller& controller, const std::string& spec, const scope& scope);
std::vector<std::unique_ptr<xml::node>> resolve_fragment_spec(xml::element* node, std::filesystem::path dir, basic_template_processor& loader, const json::element& spec, const scope& scope);
std::vector<std::unique_ptr<xml::node>> resolve_fragment_spec(xml::element* node, std::filesystem::path dir, basic_template_processor& loader, const std::string& file, const std::string& selector, bool byID);
// virtual void process_node_attr(xml::node* node, const scope& scope, std::filesystem::path dir);
AttributeAction process_attr_if(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader, bool unless);
AttributeAction process_attr_assert(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_text(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader, bool escaped);
AttributeAction process_attr_switch(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_each(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_attr(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_with(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_generic(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_boolean_value(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_inline(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_append(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader, std::string dest, bool prepend);
AttributeAction process_attr_classappend(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_styleappend(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
AttributeAction process_attr_remove(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader);
enum class TemplateIncludeAction { include, insert, replace };
AttributeAction process_attr_include(xml::element* node, xml::attribute* attr, scope& scope, std::filesystem::path dir, basic_template_processor& loader, TemplateIncludeAction tia);
std::map<std::string, attr_handler> m_attr_handlers;
xml::document m_template; // copy of the entire document...
};
}
|