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树的更多相关文章

  1. js字符串解析与转换成数字

    解析允许字符串中含有非法数字字符,解析按从左至右的顺序,如果遇到非数字字符就停止.而转换不允许出现非数字字符,否则会失败并返回NaN

  2. dom4j解析xml字符串实例

    DOM4J 与利用DOM.SAX.JAXP机制来解析xml相比,DOM4J 表现更优秀,具有性能优异.功能强大和极端易用使用的特点,只要懂得DOM基本概念,就可以通过dom4j的api文档来解析xml ...

  3. C#解析JSON字符串总结

    JSON文件读取到内存中就是字符串,.NET操作JSON就是生成与解析JSON字符串. 操作JSON通常有以下几种方式: 1. 原始方式:按照JSON字符串自己来解析. 2. 通用方式[★★★★★]: ...

  4. Json转model对象,model转json,解析json字符串

    GitHub链接: https://github.com/mozhenhau/D3Json D3Json 通过swift的反射特性,把json数据转换为model对象,本类最主要是解决了其他一般jso ...

  5. C#解析JSON字符串总结(转载)

    JSON文件读取到内存中就是字符串,.NET操作JSON就是生成与解析JSON字符串. 操作JSON通常有以下几种方式: 1. 原始方式:按照JSON字符串自己来解析. 2. 通用方式[★★★★★]: ...

  6. java解析Json字符串之懒人大法

    面对Java解析Json字符串的需求,有很多开源工具供我们选择,如google的Gson.阿里巴巴的fastJson.在网上能找到大量的文章讲解这些工具的使用方法.我也是参考这些文章封装了自己的Jso ...

  7. 一、JSON解析与字符串化

    JSON.stringify() 序列化对象.数组或原始值 语法:JSON.stringify(o,filter,indent) o,要转换成JSON的对象.数组或原始值 filter,指定要序列化的 ...

  8. Atitit.注解and属性解析(2)---------语法分析 生成AST attilax总结 java .net

    Atitit.注解and属性解析(2)---------语法分析 生成AST  attilax总结  java .net 1. 应用场景:::因为要使用ui化的注解 1 2. 使用解释器方式来实现生成 ...

  9. JackSon解析json字符串

    JackSon解析json字符串 原文:http://blog.csdn.net/java_huashan/article/details/9353903 概述 jackson解析json例子 准备工 ...

  10. java解析xml字符串(用dom4j)

    package com.smsServer.Dhst; import java.util.HashMap; import java.util.Iterator; import java.util.Ma ...

随机推荐

  1. 全网最适合入门的面向对象编程教程:47 Python函数方法与接口-回调函数Callback

    全网最适合入门的面向对象编程教程:47 Python 函数方法与接口-回调函数 Callback 摘要: 回调函数是编程中一种非常常见的模式,用于将函数作为参数传递给其他函数或方法.这种模式在 Pyt ...

  2. CSS – Monospaced font & ch unit 等宽字体与 ch 单位

    前言 在做 Statistics Counter 时, 发现总是会跳, 研究后才发现原来是等宽搞的鬼, 这篇就来说说等宽字体. 参考 等宽字体在web布局中应用以及CSS3 ch单位嘿嘿 不等宽字体 ...

  3. Identity – Options

    前言 上一篇已经有写到一些配置了, 但不完整, 这里专门写一篇吧. 防暴力登入 services.Configure<IdentityOptions>(options => { // ...

  4. Parquet.Net: 将 Apache Parquet 移植到 .NET

    Parquet.Net 是一个用于读取和写入 Apache Parquet 文件的纯 .NET 库,使用MIT协议开源,github仓库:https://github.com/aloneguid/pa ...

  5. 暑假集训SCP提高模拟10

    我(看着百度百科):我已经知道这场谁组的题了 CTH: 谁 我:你想想,能在模拟赛里塞四道数学题还玩邦的,还能有谁 CTH: 我不知道 我:我不知道 CTH: 我知道了 我:我知道了 我:我是 Bob ...

  6. 第44天:WEB攻防-PHP应用&SQL盲注&布尔回显&延时判断&报错处理&增删改查方式

    #PHP-MYSQL-SQL操作-增删改查 1.功能:数据查询 查询:SELECT * FROM news where id=$id 2.功能:新增用户,添加新闻等 增加:INSERT INTO ne ...

  7. Task 笔记

    1.计时器类Stopwatch Stopwatch stopwatch=new Stopwatch() stopwatch.Start();//开始计时 stopwatch.Stop();//停止计时 ...

  8. Adobe Pr 软件报错,此效果需要GPU加速

    事件起因: 某同事使用PR软件报错,报错截图如下:   解决办法: 1.在pr菜单栏选择文件-项目设置-常规-视频渲染和回放-渲染程序,切换到Mercury Playback Engine GPU加速 ...

  9. 开源之夏 2022 重磅来袭!欢迎报名 KubeSphere 社区项目!

    活动简介 "开源之夏(英文简称 OSPP)"是中科院软件所"开源软件供应链点亮计划"指导下的系列暑期活动,由软件所与 openEuler 社区共同主办. 开源之 ...

  10. 使用 KubeEye 为你的 K8s 集群安全保驾护航

    作者:KaliArch(薛磊),某Cloud MSP服务商产品负责人,熟悉企业级高可用/高并发架构,包括混合云架构.异地灾,熟练企业DevOPS改造优化,熟悉Shell/Python/Go等开发语言, ...