write html parser

首先需要声明 html 不能用正则表达式来直接匹配进行内容抽取等处理,这样做的结果很严重

 

Not XHTML Parser

 

另一点需要注意的是:不是构建 xhtml parser ,如果是 xhtml 的话可采用 parser generator 根据 grammar 直接生成解析器即可,而 html 由于对错误很宽容(比如普遍的标签不闭合问题),具备超强的错误纠正机制,简单的自动 parser 生成并不可行。也即 html 不是一种上下文无关 的语言。

 

对 html parser 构建有两个思路:

 

一个思路是半自动生成,先由自动生成的 parser 识别出可以识别的标签,后期再手动匹配标签 ,但这种方法对于本身标签都不完整的情况不能正确识别:

 

<div id='n

 

另一个思路就是完全手写 parser ,递归下降进行 dom 树建立,这其中可以加入很多容错处理,例如 html5 的 parse 规则。

 

Write Parser By Hand

 

手写 parser 从两方面来考虑:

 

1. tag/node 的识别。难点在于 tag 的识别:收集 tag 对应的属性以及属性值。其中词法识别过程可以采用正则表达式来识别标签名,属性名,属性值,不过为了更好的容错以及信息收集,也可以直接采用确定有穷状态机来识别。语法部分就比较简单,将成对的属性名和属性值和标签名关联起来成为 Tag 对象即可。

 

通过 1 可以识别出独立的开标签,闭标签,其他节点元素(text,comment)序列。

 

2. dom 树建立。在该步穿插调用 1 ,将配对的开闭标签组合成为一个 dom 节点。注意点在于

 

   2.1 rawtext/rcdata 的处理:当遇到 textarea ,script,style 时,其后内容的 parse 不能简单的调用 1 步,需要特殊识别对应的结束标记来结束 textarea/syle/script。例如:防止用户输入以下代码意外结束或开始标签(本质上是不符合html5 parse 规范,,规范中说明遇到结束标签会检查下结束标签是不是和当前的开始标签相同,而对 script 即是检查 xx 是不是等于 script (</xx>)):

 

 

<textarea>
 <div>
     x
  </div>
</textarea>
<script>alert("<div></div>");</script>
 

   2.2 标签闭合问题:当遇到结束标签不和当前开始标签相同,或到了parse 结尾时尚有开标签未闭合。例如:

 

 

<div>
<div>
<span>
2
 </div>

 

 

<div>1

 

   这时就需要自动补全闭合标签,对在当前递归分析栈上的开标签元素依次弹出闭合,直到当前结束标签和某个栈上的开标签名称相同或者栈中元素为空。不能匹配的闭标签做抛弃处理。

 

 

  2.3 修正 html 代码(optional)。如果需要对输出代码的质量进行控制(主要指标签嵌套检查),那么就需要在每个节点 parse 完毕后进行修正后处理(post-process),例如:

 

<a href='g.cn'>
 <div>
     1
<span>
3
</span>
<a href='z.cn'>
4
</a>
2
  </div>
</span>
 

修正后的 dom 树对应的 html 为:

 

<div>
     <a href='g.cn'>1
<span>
3
</span>
</a>
<a href='z.cn'>
4
</a>
<a href='g.cn'>
2
</a>
  </div>
 

将嵌套关系错误的元素正确应用到真正需要的对应节点上去。具体对于行内元素 a 包含块状元素 b 的情况,那么该行内元素 a 就需要递归嵌套到块状元素 b 的所有行内元素上去(注意消重)。而对于

 

<div><li>1</li>
<li>2</li>
</div>

 

则需要生成固定的父元素标签 ul:

 

<ul>
	<li>
		1
	</li>
	<li>
		2
	</li>
</ul>
 

 

Scenario

 

常见的应用场景包括: html 代码美化与压缩,高效客户端过滤,规范,检测用户输入的 html (dom-free)。

 

具体到压缩处理 又包含

 

去除默认属性,

合并连续空白,

去除注释,

属性值引号/属性值条件去除,

闭合闭合标签(</body> </html></option> </li>)条件去除

...

 

而这一切都是在 parse 后进行。

 

DEMO

 

html 代码美化与压缩

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值