如果您以前问我这个问题,我会说,肯定很难吧,我们用用开源项目就好。
何必重复造轮子?
应不应该重复造轮子呢?
我想每个人心中都有答案。但是我鼓励大家,我们一起重复造轮子。
后续会出一篇文章,关于Chat的文章。是的,不是ChatGPT,是Chat,没有机器学习,我们普通研发人员,也应该继续前进,当然还是和正则表达式有关系。
现在,我们回到今天的话题,正则表达式实例与HTML语法树。
前面的文章,我们知道了,怎么匹配HTML标签,怎么匹配HTML标签属性,今天我们从零实现一个HTML语法树。
看这篇文章之前,建议先看前面两篇文章,如果您对正则非常熟悉,那么现在就开始吧。
在开始前,我们需要整理需求,我们需要知道,一个完整的HTML文档,最基本的语法,标签以及不同框架增加的特殊属性等,我们因该如何去匹配实现。
为什么要加上其它框架属性,因为当时想通过一套代码生成VUE、React版本。[我想静静]
下面截图文档中,基本囊括了,一个HTML文档的所有情况信息,您可以仔细看下。其中包括(注释、文档声明、单标签、双标签、样式、脚本、有属性值属性、属性名即属性值属性、第三方框架属性等)。
const reg_comment = /<!--.*?-->/s;
const reg_doctype = /]*>/i;
const reg_element = /<[^/!]((["'])+.*?2|[^>])+>/
const reg_elementEnd = /</.*?>/
<p>p>
var reg_tagName = /(?<=<[/s]*)w+(?=(s+(?![s=])|>))/;
type='text' disabled value="" class="txt txt-md" v-on:click="save('button')" />
const reg_tagAttrs = /(?<=s)[w:.-@]+(=(["']).*?2)*/g;
v-on:click="save('button')"
var reg_tagAttrDatas = /(^[^=]+|(?<=(['"])).*?(?=2))/g;
查阅了相关资料、同时编写Demo案例验证、对于Javascript版本的正则表达式,发现对于嵌套匹配目前支持不完善,所以放弃这种方式。
当然,也有可能,我挖掘的还不够深入。
怎么理解?
请看下面的例子。
html,body {width: 100%;height: 100%;margin: 0;padding: 0;}
看到这个例子,你大概明白。就是一行一行的匹配,或者说每次只匹配一种类型。
1、遇到非input、img、link、hr、br这几个单行标签,或者>结束标记,就向下递归。
2、遇到结束标记>,就返回上一层。
3、遇到style、script标签,他们内部的内容,直接按文本处理。
到这,我想部分朋友,都不需要看代码实例,都知道怎么实现了。
测试代码从PrvtCMS中,临时拆分出来的,只要思路有了,实现起来还是很容易。
const reg_tagName = /(?<=<[/s]*)w+(?=(s+(?![s=])|>))/;
const reg_tagAttrs = /(?<=s)[w:.-@]+(=(["']).*?2)*/g;
const reg_tagAttrDatas = /(^[^=]+|(?<=(['"])).*?(?=2))/g;
const regMap = new Map();
regMap.set("element", /^<[^/!]((["'])+.*?2|[^>])+>/);
regMap.set("elementEnd", /</.*?>/);
regMap.set("note", /<!--.*?-->/is);
regMap.set("declare", //i);
regMap.set("text", /^[^<>]+/);
/**
* 返回Json语法树
* @param {父节点名称} name
* @param {被解析的html} htmlContent
* @param {节点集合} nodes
*/
const toJson = (name, htmlContent, nodes) => {
regMap.forEach((value, key) => {
if (key !== "elementEnd") {
let res = regFirstResult(value, htmlContent);
if (res.length) {
htmlContent = toNext(name, res, key, htmlContent, nodes);
}
}
});
// 处理同级
let res = regFirstResult(regMap.get("element"), htmlContent);
if (res.length) return toJson(name, htmlContent, nodes);
return htmlContent;
};
/**
* 下一匹配
* @param {父节点名称} name
* @param {匹配结果} parseRes
* @param {匹配类型} nodeType
* @param {被解析的html} htmlContent
* @param {节点集合} nodes
* @returns
*/
const toNext = (name, parseRes, nodeType, htmlContent, nodes) => {
if (nodeType == "elementEnd")
return parseElementEnd(name, parseRes, nodeType, htmlContent, nodes);
if (nodeType == "element")
return parseElement(name, parseRes, nodeType, htmlContent, nodes);
return parseText(name, parseRes, nodeType, htmlContent, nodes);
};
const nodes = [];
toJson("", strHtml, nodes);
console.log(JSON.stringify(nodes));
了解或者使用Svelte、Angular、Vue、React、Htmx、Qwik、Astro、Web Component等等技术,AST似乎无处不在。
所以一起重复造轮子吧。
PrvtCMS模板在线管理、支持实时预览、跨模板、跨组件引用等。能实现这些功能的基础就是写了一个HTML语法树。是的,重复造轮子。
……思考中……
人人为我,我为人人,欢迎您的浏览,我们一起加油吧。
页面更新:2024-05-31
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号