博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

处理 HTML 的 HtmlDocument 类实现

Posted on 2011-01-02 23:46  xuld  阅读(2126)  评论(1编辑  收藏  举报

一个 XML 处理很复杂, 但在 .net 却非常方便, 因为系统已提供了 Xml 处理的工具。

一个 Xml 的文件处理是这个格式:

XmlDocument xml = new XmlDocument();

xml.Load("aa.xml");

xml.AppendChild(xml.CreateElement("r"));


 

但是 HTML 就不如此方便了, 当然 .net 有 HtmlDocument 类 (不知道 ? )

 

System.Windows.Form.UI.HtmlDocument   这是控件, 内部是 mshtml.dll 完成, 在 web 就无法使用了。

 

所以非常要做一个 像 XML 一样处理 HTML 的类。

操作 HTML 可以

HtmlDocument html = new HtmlDocument();

html.Load(new Uri(http://www.baidu.com));

html.GetElementById("name").Value = "3";
 

那就非常好了。

 

XML 和 HTML 可以解释为继承  HTML 来自 XML

 

XmlDocument 类的许多成员在 HtmlDocument 也存在

 

且 HtmlDocument 还有 GetElementById GetElementsByName 的函数

 

HtmlDocument 的成员不可自定义, 而是有标准的规范的。  

首先 要知道:

HTMLNode 其实是1个单链表。

各元素之间 上一个节点指下个节点。 最后一个节点指父节点。

我之所以强调是因为很多人和我一样一直把它作为非链表的。

 

所以 HtmlNode集合其实是空的,只是提供游走链表的东西。

 

第二:

和 XML 相比,  HTML 处理节点时不同的地方,也是写这个类最困难的地方:

HTML 可以不规范。

 

如下:

<html><head></html>

 

这对 XML 来说,是个抛出异常的好地方

XML说: 你给的东西不像话,我不干了, 杂的?

HTML说: 我很友善,我耐心的告诉你啥错了,我帮你修复。

 

于是 HTML 处理相当复杂。

如果碰到一个 </html> 其父节点不是 <html> 则应加入 </head>  。

类似一个栈, 有进必要出, 没出就抓出来

 

第三:

<p> 是讨厌的东西,因为 <p></p> 或 <p> 都合法。 需要获得下个节点才能决定<p>

一些<br> 之类的也有额外处理

 

接下来,可以开做了:

 

先写 HtmlNode 类

public abstract class HtmlNode {

     public string NodeName { get; set; }

    public NodeType NodeType  { get; set; }

    public HtmlNode NextSilding   { get; set; }

}


 

然后是 HtmlAttributionCollection, HtmlAttribution

然后是 HtmlElement 类

 

public class  HtmlElement : HtmlNode {

  HtmlAttributionCollection Attributions;

     public string TagName   {get; set;}

}


 

最后是 HtmlDocument

 

这些类做好后,继续 词法分析工具

名字为   

HtmlParser

 

这个类负责读取html  , 并获取当前位置,如 <html><head id="d">s</html>

将处理为

<html>

<head id="d">

s

 </html>


 

这样就可知道基本的内容。

 

最后 HtmlLoader   为节点语法分析

HtmlLoader 有个跟节点(默认 HtmlDocument)

每次载入节点都存至跟节点。  ( 适合 InnerHTML = "" 调用)

HtmlLoader 管理一个栈,负责调整树。

如发现<html> 压入。

发现 </html> 把栈内所有<html>之外的都移除, 再移除  <html>

 

最后加点常用元素

如 HtmlImageElement , 这样就是完整的 HTML 工具

 

在系统的 XML 中 使用了 NameTable 实现字符串缓存。

这个缓存由2个优点:

  避免同一个 字串占多个位置

  比较字串只要比较字符的引用,达到高速的比较。

 

因此 HTML 同样可以这样操作


 最后, 作为 HTML 处理, 当然得提供类似浏览器的一些操作,如表单的提交。

因此 特地准备了 Form 节点, 提供提交函数,将文档值处理后上交。

这可以实现自动填 form ,自动登录等。

当然速度肯定比用控件好多,不过无法处理js部分。