解析HTML字符串成AST树
1. 如何将一个字符传转换成一个AST树结构。
直接上代码:
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`
const qnameCapture = `((?:${ncname}\\:)?${ncname})`
// 匹配 <div
const startTagOpen = new RegExp(`^<${qnameCapture}`)
// 匹配 > />
const startTagClose = /^\s*(\/?)>/
// 匹配 </div>
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`)
const doctype = /^<!DOCTYPE [^>]+>/i
//注意树形的html 只能有一个根节点
function parseHtmlToAst(html){
let text,root,currentParent,stack=[];
while(html){
let textEnd=html.indexOf("<");
if(textEnd===0){
//查找开始tag
const startTagMatch=parseStartTag();
if(startTagMatch){
//生成AST树
start(startTagMatch.tagName,startTagMatch.attrs);
continue;
}
//查找结束标签
const endTagMatch=html.match(endTag);
if(endTagMatch){
advance(endTagMatch[0].length);
//构造ast树
end(endTagMatch[1]);
continue;
}
}
//文本节点
if(textEnd>0){
text=html.substring(0,textEnd);
}
if(text){
//截取字符串
advance(text.length);
chars(text);
}
}
//截些开始标记
function parseStartTag(){
const start=html.match(startTagOpen);
let end,attr;
//找到开始标记
if(start){
const match={
tagName:start[1],
attrs:[]
}
advance(start[0].length)
//配置属性
while(!(end=html.match(startTagClose)) && (attr=html.match(attribute))){
match.attrs.push({
name:attr[1],
value: attr[3] || attr[4] || attr[5]
})
advance(attr[0].length);
}
//匹配结束字符 > 或 />
if(end){
advance(end[0].length);
return match;
}
}
}
//截取字符串
function advance (n) {
html = html.substring(n)
}
//构造AST树形
function start(tagName,attrs){
const element=createAstElement(tagName,attrs);
if(!root){
root=element;
}
currentParent=element;
stack.push(element);
}
//结束钩爪树形
function end(tagName){
const element=stack.pop();
currentParent=stack[stack.length-1];
if(currentParent){
element.parent=currentParent;
currentParent.children.push(element);
}
}
//处理文本节点
function chars(text){
text=text.trim();
if(text.length>0){
currentParent.children.push({
type:3,
text
})
}
}
function createAstElement(tagName,attrs){
return {
tag: tagName,
type: 1,
children:[],
attrs,
parent
}
}
return root;
}
let html=`<div id="app" style="color:red;width:200px">
你好:{{name}}
<span class="text" style="color:green">{{age}}
</span>
</div>
`;
let root=parseHtmlToAst(html);
console.info(root)
代码的逻辑是:
对字符串的处理,从头开始处理,先找 < 开头的字符,如果找到则用 正则表达式查找 <div 的标签,找到后,截取 后面的字符串,然后循环查找 属性,直到 找到 > 或 />字符为止,找到让后截取后面的字符串。
中间用到了堆栈作为树节点作为串联。
2.构造结果

解析HTML字符串成AST树的更多相关文章
- js字符串解析与转换成数字
解析允许字符串中含有非法数字字符,解析按从左至右的顺序,如果遇到非数字字符就停止.而转换不允许出现非数字字符,否则会失败并返回NaN
- dom4j解析xml字符串实例
DOM4J 与利用DOM.SAX.JAXP机制来解析xml相比,DOM4J 表现更优秀,具有性能优异.功能强大和极端易用使用的特点,只要懂得DOM基本概念,就可以通过dom4j的api文档来解析xml ...
- C#解析JSON字符串总结
JSON文件读取到内存中就是字符串,.NET操作JSON就是生成与解析JSON字符串. 操作JSON通常有以下几种方式: 1. 原始方式:按照JSON字符串自己来解析. 2. 通用方式[★★★★★]: ...
- Json转model对象,model转json,解析json字符串
GitHub链接: https://github.com/mozhenhau/D3Json D3Json 通过swift的反射特性,把json数据转换为model对象,本类最主要是解决了其他一般jso ...
- C#解析JSON字符串总结(转载)
JSON文件读取到内存中就是字符串,.NET操作JSON就是生成与解析JSON字符串. 操作JSON通常有以下几种方式: 1. 原始方式:按照JSON字符串自己来解析. 2. 通用方式[★★★★★]: ...
- java解析Json字符串之懒人大法
面对Java解析Json字符串的需求,有很多开源工具供我们选择,如google的Gson.阿里巴巴的fastJson.在网上能找到大量的文章讲解这些工具的使用方法.我也是参考这些文章封装了自己的Jso ...
- 一、JSON解析与字符串化
JSON.stringify() 序列化对象.数组或原始值 语法:JSON.stringify(o,filter,indent) o,要转换成JSON的对象.数组或原始值 filter,指定要序列化的 ...
- Atitit.注解and属性解析(2)---------语法分析 生成AST attilax总结 java .net
Atitit.注解and属性解析(2)---------语法分析 生成AST attilax总结 java .net 1. 应用场景:::因为要使用ui化的注解 1 2. 使用解释器方式来实现生成 ...
- JackSon解析json字符串
JackSon解析json字符串 原文:http://blog.csdn.net/java_huashan/article/details/9353903 概述 jackson解析json例子 准备工 ...
- java解析xml字符串(用dom4j)
package com.smsServer.Dhst; import java.util.HashMap; import java.util.Iterator; import java.util.Ma ...
随机推荐
- 【倒计时3天】“CSIG企业行”走进合合信息,大咖解密智能文档处理背后的底层技术及AI未来展望
3月18日,由中国图象图形学会(CSIG)主办,合合信息.CSIG文档图像分析与识别专业委员会联合承办的"CSIG企业行"系列活动将正式举办,通过搭建学术界与企业交流合作平台,为企 ...
- BOOST 环形队列circular_buffer
BOOST库的环形队列比较灵活,前插或后插,删除队首或删除队尾元素,都支持. 只贴代码: #include <boost/circular_buffer.hpp> #include < ...
- for循环遍历的盗版笔记
遍历一个List有如下几种方法 5 6 是 java8 增强for循环底层由Iterator实现 增强for的出现时替代迭代器的,所以在遍历集合或者遍历数组就可以使用增强for去完成 增强for循 ...
- 《你必须掌握的Entity Framework 6.x与Core 2.0》代码下载
https://item.jd.com/12376014.html<你必须掌握的Entity Framework 6.x与Core 2.0>代码下载,共享代码: https://git ...
- Linux内核中cpu_capacity是什么?
cpu_capacity 在Linux内核中,cpu_capacity 是用于表示每个CPU的处理能力的一个参数,通常用于调度器的负载均衡.它表明不同的CPU核心在计算资源分配中的相对性能,尤其在异构 ...
- 4.3.2 等比数列的前n项和公式
\({\color{Red}{欢迎到学科网下载资料学习 }}\) [ [基础过关系列]高二数学同步精品讲义与分层练习(人教A版2019)] ( https://www.zxxk.com/docpack ...
- C++第六节课 引用变量 指针的升级版
#include <iostream> using namespace std; // C++的引用 是C指针的升级 可以提高代码的稳定性和健壮性 // const 修饰的引用 是 常引用 ...
- ORM的设计思想
1 以面向对象的思想来完成对于数据库的操作! 2 万物皆对象
- 最详细CentOS7.6安装openGauss5.0.3教程
一.环境准备 1.1 主机信息 项目 内容 操作系统 CentOS7.6 IP 192.168.4.201 主机名 opgs201 CPU 8core 内存 16GB 磁盘1 100GB 1.2 操作 ...
- 强大的无头UI表格库:TanStack Table!Github Star达到了惊人的25K!
强大的无头UI表格库:TanStack Table!Github Star达到了惊人的25K! 在构建现代化 Web 应用时,表格和数据网格是常见的 UI 组件,特别是在处理大量数据或需要复杂交互时, ...