HtmlRender - c++实现的html生成类

HtmlRender

CppTinParser/render.hpp中定义和实现。

使用c++实现的简易Html编辑类。

简介

目前,c++有几个Html解析器,而少见便捷规范的html生成器,HtmlRender则提供了一个简单的、规范的html内容生成器。用c++实现html内容生成器,并不是简单的字符串拼接,这样会导致代码编写不规范、易读性下降,而且无法应对复杂html生成任务。HtmlRender借鉴了python的第三方html编写库——dominate


使用接口

初始化

HtmlRender* item = HtmlRender(string tag, string content, map<string,string> kws, bool onetag=false, bool pre=false)
//tag 标签名称,如果为空字符串,则在生成时直接产生content,不添加标记
//content 标签内容
//kws 标签参数
//onetag 是否为单标签,比如<br>, <hr>等
//pre 是否显示为原文本

生成html文本

string result = HtmlRender.render()

该函数将生成并返回该HtmlRender所包含的html文本内容。一般应只用tag = "html"HtmlRender使用该函数,以此来实现完整的html文本。当然,任意HtmlRender实例均可,单标签也可使用该函数,但是生成内容将大概率出现错误。

添加子元素

为了方便操作,HtmlRender使用list作为容器来存取子元素指针,这里的子元素同样是HtmlRender。具体增加代码如下:

HtmlRender* subitem = new HtmlRender(...)
item.add(subitem)

如果父元素本身就是通过new创建,则使用如下代码:

item->add(subitem)

设置标签元素内容和参数

设置内容:

item.configcnt(string content)

设置参数:

item.configkws(map<string, string> kws)

获取父元素指针

除了顶级元素,任何一个标签元素在被使用add方法后,都会有明确的父元素。

通过如下代码获取父元素指针:

HtmlRender* p_item = subitem->parent()
//p_item == &item

获取子元素指针列表

如果一个元素使用了add方法,则必然含有子元素。

使用如下代码获取子元素指针列表

list<HtmlRender*> children = item.children()

实现原理

添加子元素

获取子元素指针,在子元素指针列表中添加该指针。

void HtmlRender::add(HtmlRender* item) {
    //添加html内容
    this->htmlcontent.push_back(item);
    item->_parent = this;
}

渲染

首先生成元素自身标签、参数、内容,然后遍历子元素指针列表,获取所有子元素以及多级子元素的渲染生成内容,最后加上自身结束标签(如果有的话)。

string HtmlRender::render() {
    //渲染为html文本
    if (this->tag == ""){
        return this->content;
    }
    string htmltext = "<" + this->tag;
    for (auto &kw : this->kws) {
        htmltext += " " + kw.first + "=\"" + kw.second + "\"";
    }
    htmltext += ">";

    htmltext += this->content;
    
    for (auto item = this->htmlcontent.begin(); item != this->htmlcontent.end(); ++item) {
        string subtext = (*item)->render();
        htmltext += "\n" + subtext;
    }

    if (this->onetag){
        //单标签
        htmltext += "\n";
    }else{
        htmltext += "\n</" + this->tag + ">";
    }
    return htmltext;
}


示例

测试代码:

int main(){
	HtmlRender html = HtmlRender("html", "", {});
	HtmlRender* head = new HtmlRender("head", "", {});
	HtmlRender* title = new HtmlRender("title", "TinML", {});
    head->add(title);
	html.add(head);
	
	HtmlRender* body = new HtmlRender("body", "", {});
	html.add(body);
	
	HtmlRender* t1 = new HtmlRender("h1", "TITLE", {});
	body->add(t1);
	for (int i=0; i<10; i++){
		HtmlRender* p = new HtmlRender("p", "paragraph - " + to_string(i), {});
		body->add(p);
	}
	
	string htmltext = html.render();
	cout << htmltext <<endl;
	
	return 0;
}

结果:

<html>
<head>
<title>TinML
</title>
</head>
<body>
<h1>TITLE
</h1>
<p>paragraph - 0
</p>
<p>paragraph - 1
</p>
<p>paragraph - 2
</p>
<p>paragraph - 3
</p>
<p>paragraph - 4
</p>
<p>paragraph - 5
</p>
<p>paragraph - 6
</p>
<p>paragraph - 7
</p>
<p>paragraph - 8
</p>
<p>paragraph - 9
</p>
</body>
</html>

主要源码

string subreplace(std::string resource_str, std::string sub_str, std::string new_str){
    string dst_str = resource_str;
    string::size_type pos = -1;
    //这里要专门处理&转义后仍存在的&符号,所以find使用了pos
    while((pos = dst_str.find(sub_str, pos+1)) != std::string::npos)   //替换所有指定子串
    {
        dst_str.replace(pos, sub_str.length(), new_str);
    }
    return dst_str;
}

class HtmlRender {
    //html编辑类
public:
    HtmlRender()=default;
    HtmlRender(string tag, string content, map<string,string> kws, bool onetag=false, bool pre=false){
        this->tag = tag;
        // this->content = content;
        // this->kws = kws;
        this->pre = pre;
        if (pre){
            //原文本内容
            this->content = content;
        }else{
            this->load_content(content);
        }
        this->load_kws(kws);
        this->onetag = onetag;

        this->_parent = NULL;
    }
    HtmlRender* _parent;//父节点
    string render();//输出html文本
    void add(HtmlRender* item);//添加html内容
    void configcnt(string content);//配置html内容
    void configkws(map<string, string> kws);//配置html内容
    HtmlRender* parent();
    list<HtmlRender*> children();//获取子HtmlRender内容
private:
    list<HtmlRender*> htmlcontent;//html文件内容
    string tag;//html标签
    string content;//标签内容
    map<string, string> kws;//html关键字
    bool onetag;//是否为单标签
    bool pre;//是否为原文本内容

    const map<string, string> ascii_ent = { { "\"", "quot" }, { "\'", "apos" }, { "&", "amp" }, { "<", "lt" }, { ">", "gt" } };//ascii转义

    void load_content(string content);//加载内容
    void load_kws(map<string, string> kws);//加载关键字
    string escape_ascii(string content);//转义ascii字符

};

string HtmlRender::render() {
    //渲染为html文本
    if (this->tag == ""){
        return this->content;
    }
    string htmltext = "<" + this->tag;
    for (auto &kw : this->kws) {
        htmltext += " " + kw.first + "=\"" + kw.second + "\"";
    }
    htmltext += ">";

    htmltext += this->content;
    
    for (auto item = this->htmlcontent.begin(); item != this->htmlcontent.end(); ++item) {
        string subtext = (*item)->render();
        htmltext += "\n" + subtext;
    }

    if (this->onetag){
        //单标签
        htmltext += "\n";
    }else{
        htmltext += "\n</" + this->tag + ">";
    }
    return htmltext;
}

void HtmlRender::add(HtmlRender* item) {
    //添加html内容
    this->htmlcontent.push_back(item);
    item->_parent = this;
}

void HtmlRender::configcnt(string content) {
    //配置html内容
    if (this->pre){
        //原文本内容
        this->content = content;
    }else{
        string ascii_ent = this->escape_ascii(content);
        this->content = ascii_ent;
    }
 }

void HtmlRender::configkws(map<string, string> kws) {
    //配置html内容
    for (auto &kw : kws) {
        string value = kw.second;
        string ascii_ent = this->escape_ascii(value);
        kw.second = value;
    }
    this->kws = kws;
 }

HtmlRender* HtmlRender::parent() {
    return this->_parent;
}

list<HtmlRender*> HtmlRender::children() {
    return this->htmlcontent;
}

void HtmlRender::load_content(string content) {
    //加载内容
    string ascii_ent = this->escape_ascii(content);
    this->content = ascii_ent;
 }

void HtmlRender::load_kws(map<string, string> kws) {
    //加载关键字
    for (auto &kw : kws) {
        string value = kw.second;
        string ascii_ent = this->escape_ascii(value);
        kw.second = value;
    }
    this->kws = kws;
 }

string HtmlRender::escape_ascii(string content) {
    //转义ascii字符
    for (auto &item : this->ascii_ent) {
        content = subreplace(content, item.first, "&" + item.second + ";");
    }
    return content;
 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/879063.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

kubernetes技术详解,带你深入了解k8s

目录 一、Kubernetes简介 1.1 容器编排应用 1.2 Kubernetes简介 1.3 k8s的设计架构 1.3.1 k8s各个组件的用途 1.3.2 k8s各组件之间的调用关系 1.3.3 k8s的常用名词概念 1.3.4 k8s的分层结构 二、k8s集群环境搭建 2.1 k8s中容器的管理方式 2.2 k8s环境部署 2.2.1 禁用…

定位HardFault

一、HardFault定义 STM32出现HardFault_Handler硬件错误的原因主要有两个方面&#xff1a; 1、内存溢出或者访问越界。&#xff08;包括使用野指针&#xff09; 2、堆栈溢出。 二、定位HardFault步骤 1. 判断所使用堆栈&#xff1a; 发生异常之后可首先查看LR寄存器中的值…

SAP B1 单据页面自定义 - 用户界面编辑字段

背景 接《SAP B1 基础实操 - 用户定义字段 (UDF)》&#xff0c;在设置完自定义字段后&#xff0c;如下图&#xff0c;通过打开【用户定义字段】可打开表单右侧的自定义字段页。然而再开打一页附加页面操作繁复&#xff0c;若是客户常用的定义字段&#xff0c;也可以把这些用户…

pytest 接口测试

pytest 核心重点 读取excel&#xff08;xfile --> read&#xff09; 函数循环执行( pytest 装饰器&#xff0c;自动解析&#xff0c;一个个单独执行&#xff09; 接口关联&#xff08;Template 处理参数变量&#xff09; pytest 是什么 .py文件名 用 test_开头&#xff0c;…

【计算机网络】HTTP相关问题与解答

此篇文章内容会不定期更新&#xff0c;仅作为学习过程中的笔记记录 目录 一、HTTP请求和响应报文是怎样的&#xff1f; 1、请求报文 2、响应报文 二、HTTP请求方法有哪些&#xff1f; GET HEAD POST PUT DELETE PATCH OPTIONS TRACE CONNECT 三、GET请求与POST请…

linux cmake版本升级教程(Centos7)

有时候,当前系统的cmake版本,并一定能满足编译要求,所以需要进行升级到高于某个版本才能正常编译。本章教程,主要在centos7上进行升级cmake版本。 一、查看当前的cmake版本 cmake --version二、下载指定版本的cmake wget https://github.com/Kitware/CMake/releases/down…

Element UI:初步探索 Vue.js 的高效 UI 框架

Element UI&#xff1a;初步探索 Vue.js 的高效 UI 框架 一 . ElementUI 基本使用1.1 Element 介绍1.2 Element 快速入门1.3 基础布局1.4 容器布局1.5 表单组件1.6 表格组件1.6.1 基础表格1.6.2 带斑马纹表格1.6.3 带边框表格1.6.4 带状态的表格 1.7 导航栏组件讲解 二 . 学生列…

安装WINDOWS微软商店已下架的WSL系统,以UBUNTU 16.04 为例

下载WSL系统 方法1&#xff1a;POWERSHELL 用powershell下载 PowerShell Invoke-WebRequest -Uri https://aka.ms/wsl-ubuntu-1604 -OutFile Ubuntu.appx -UseBasicParsing 1 如果下载时间很长&#xff0c;可以这样把进度条关闭&#xff1a; $ProgressPreference Silentl…

计算机人工智能前沿进展-大语言模型方向-2024-09-12

计算机人工智能前沿进展-大语言模型方向-2024-09-12 1. PharmaBench: Enhancing ADMET benchmarks with large language models Z Niu, X Xiao, W Wu, Q Cai, Y Jiang, W Jin, M Wang… - Scientific Data, 2024 大语言模型在药物发现中的应用&#xff1a;PharmaBench 文章由…

vue 实现tab菜单切换

1、目标&#xff1a; 实现切换tab菜单&#xff0c;激活状态&#xff0c;按钮高亮&#xff0c;显示对应的菜单内容 2、实现 <template><div class"tan_menu"><ul class"container"><liclass"item"v-for"item in tab…

反编译classes.dex安卓源码 文件-android反编译技术

一、安卓源码 通过解压我们得到dex文件 将dex转换为jar&#xff0c;就可以直接查看源码 二、阿雪技术观 拥抱开源与共享&#xff0c;见证科技进步奇迹&#xff0c;畅享人类幸福时光&#xff01; 让我们积极投身于技术共享的浪潮中&#xff0c;不仅仅是作为受益者&#xff0c…

fiddler抓包03_汉化

Fiddler安装后为英文界面&#xff1a; 【汉化步骤】 ​① 下载汉化文件&#xff0c;链接: https://pan.baidu.com/s/1c13Dh--TwSCbwHykO8KAug?pwd8nvn 提取码: 8nvn ② 进入Fiddler目录&#xff0c;如我的安装在E:\test\Fiddler&#xff0c;将FiddlerTexts.txt复制到E:\tes…

【Linux】生产者消费者模型:基于阻塞队列,使用互斥锁和条件变量维护互斥与同步关系

目录 一、什么是生产者消费者模型 二、为什么要引入生产者消费者模型&#xff1f; 三、详解生产者消费者模型 ​编辑 生产者和生产者、消费者和消费者、生产者和消费者&#xff0c;它们之间为什么会存在互斥关系&#xff1f; 生产者和消费者之间为什么会存在同步关系&…

C++基础知识7 list

list 1. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.2.5 list modifiers1.2.6 list的迭代器失效 2.1 模拟实现list 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 l…

基于扣子(Coze)打造第一个智能体——个性化对话机器人

文章目录 一&#xff0c;智能体体验二&#xff0c;动手打造一个自己的智能体1&#xff0c;主页点击创建机器人1.1 创建一个新的机器人1.2 修订Bot基础信息1.3 工具编排信息修订人设和回复逻辑、增补开场白等 2&#xff0c;使用插件优化机器人3&#xff0c;使用工作流优化机器人…

基于SpringBoot实现SpringMvc上传下载功能实现

目录 SpringMvc上传下载功能实现 1.创建新的项目 1&#xff09;项目信息填写 2&#xff09;选择所用的包 3&#xff09;创建controller包 4&#xff09;创建DownLoadController类 5&#xff09;创建UpLoadController类 6&#xff09;创建index.html 7&#xff09;创建upload.h…

dubbo三

dubbo dubbo架构各层说明 URL举例解析 消费者引用服务过程 项目初始化

nginx服务介绍

nginx 安装使用配置静态web服务器 Nginx是一个高性能的Web服务器和反向代理服务器&#xff0c;它最初是为了处理大量并发连接而设计的。Nginx还可以用作负载均衡器、邮件代理服务器和HTTP缓存。它以其轻量级、稳定性和高吞吐量而闻名&#xff0c;广泛用于大型网站和应用中 Ngin…

SpringCloud Feign 以及 一个标准的微服务的制作

一个标准的微服务制作 以一个咖啡小程序项目的订单模块为例&#xff0c;这个模块必将包括&#xff1a; 各种实体类&#xff08;pojo,dto,vo....&#xff09; 控制器 controller 服务类service ...... 其中控制器中有的接口需要提供给其他微服务&#xff0c;订单模块也需要…

55.【C语言】字符函数和字符串函数(strstr函数)

11.strstr函数 *简单使用 strstr: string string cplusplus的介绍 点我跳转 翻译: 函数 strstr const char * strstr ( const char * str1, const char * str2 ); 或另一个版本char * strstr ( char * str1, const char * str2 ); 寻找子字符串 返回指向第一次出现在字…