Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1639557
  • 博文数量: 584
  • 博客积分: 13857
  • 博客等级: 上将
  • 技术积分: 11883
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-16 09:34

分类: LINUX

2010-11-11 11:33:01

1.4.1  确定要实现的基本功能

鉴于对浏览器开发难度的充分考虑,以及现有人员的水平,拟定实现以下功能,以及需要考虑但暂不予实现的功能。

需要实现的包括:

(1) 界面:包括窗口,菜单,输入框,工具条,滚动条等的支持。

(2) 词法分析:必须实现实用的HTML词法分析,支持HTML4.0全部元素。

(3) 实现简单网页的布局:实现对简单网页的查看。

(4) 支持基本IO,支持采用线程的网络传输。

需要考虑的功能:

(1) JavaScript支持

(2) 汉字支持

(3) 图片格式支持

(4) 表单支持

(5) 页面元素的消息响应

1.4.2  人员分工

由于情况的变动,造成了人员比较紧张,在前期准备工作中,人力充沛,使得收集的资料比较完备,打下了较好的基础。在后期简化了目标,虽然人员减少,但也能够实现主要的工作。考虑到网络是比较独立的部份,把它分出去由专人负责。


 

第二章 HTML词法分析器的设计及其应用

 

HTML词法分析是浏览器设计的基础环节之一,也是整个设计过程中重要的前端工作,其数据结构的拟定与接下来的语法分析和布局算法密切相关,词法分析的效率与准确性、容错性也关系到整个浏览器设计的质量。

 

下面将介绍一个HTML词法分析器——Bit Token的设计思路。

 

Bit Token是Netbit Browser的HTML词法分析器,使用标准C编程,Netbit Browser是基于Linux/Gtk的浏览器,开放源码项目,

 

2.1            Bit Token的组成及其功能

Bit Token作为Netbit Browser的词法分析部份,负责对接收的HTML代码进行词法分析,主要的目的是提取网页中元素的名称及其属性,并以恰当的形式(即按一定的数据结构)加以保存,也就是完成了将数据流离散化、结构化的过程。

 

主要由以下几个部分组成:

1、初始化:完成对数据结构的初始化,主要是分配内存,变量赋初值。

2、主体的数据流分析:逐字符的进行判断,确定数据的归属类型。

3、元素的分析:提取元素的名称、属性和值域。

4、释放:主要是对内存的释放。

2.2            数据结构

typedef struct BitTokenContext

{char * strBuffer;         //当前正在处理的HTML代码

int    bufferLength;

int    curPosition;

char * global_strBuffer;    //全局HTML代码

int    global_bufferLength;

int    global_curPosition;

BitTokenList *tokenList;    //元素节点链表

BitTokenList *tokenList_tail;

BitPTagList pTagList;       //元素名称表,指向静态数据

}BitTokenContext,*BitPTokenContext;

 

BitTokenContext是用于存储当前待分析网页全局属性的数据结构,其中TokenList是核心的元素节点链表。词法分析的目的就是生成这样一个链表。下面给出该链表的数据结构,是很简单的双向链表。

 

typedef struct TokenList

{ BitToken *token;  //元素节点

 struct TokenList *priou;

 struct TokenList *next;

}BitTokenList,*BitPTokenList;

 

以下是元素节点的数据结构:

 

typedef struct BitToken

{int type;  //节点类型,如定义的HTML_BODY,HTML_TXT等。

char *pData; //如果是HTML_TXT型元素,则为其内容,否则为空

BOOL end;    //是否是结束元素,如

BitTokenAttrList *attrList; //元素属性链表,因为可能有多个属性,所以使用链表存储

BitTokenAttrList *attrList_tail;

}BitToken,*BitPToken;

 

请注意,以上出现tail标记的指针变量,如BitTokenList * tokenList_tail等,其作用是用于保存链表结尾节点指针,便于在释放内存时,直接找到链尾,提高了算法的效率。

 

2.3            算法

2.3.1 基本算法:

 

首先介绍基本的算法:

(1) 从存储网页的字符串中,顺序读入一个字符

 

(2) 如果遇到 < ,认为遇到TAG(元素),处理该元素,使用函数Token_ConsumTag(),处理完毕后,指针移到该元素尾。

   

(3) 如果遇到回车、空格,则跳过。

 

(4) 如果遇到 > ,则跳过(不应该出现此情况,为了容错)。

   

(5) 如果非以上情况,则认为遇到文字,处理这段文字,使用函数Token_Consum_PlainText()。处理完毕,指针指向下一个元素首。

 

(6) 循环以上操作,直到该网页分析完毕。

   

由此看来,主算法十分简单而清晰,主要是Token_ConsumTag()和Token_Consum_PlainText()这两个函数起关键作用,由于其中涉及到许多细节问题,此处不予详述。

 

2.3.2 算法效率与改进:

采用以上的基本算法,是可用的,但当网页比较大的时候,比如600K,该算法的效率成倍下降,这主要是由于要处理的字符串太大,在内存中完成查找、 替换、复制、移动等操作,响应时间明显下降。对此的改进办法就是分段进行词法分析,不仅极大的提高了效率(在某些情况下约提高30倍),也有利于浏览器整 体设计,因为当网页较大时,若等待全部内容传输完毕,再一次性完成词法分析和布局,用户会感到等待时间过长,一般现在成熟的浏览器都采用边传输,边分析, 边显示。

 

分段进行词法分析的算法复杂度明显增加,比如,当每段定为1024字节,在第1024字节处,可能正好将一个完整元素截断,按常规分析方法会造成错误。解决的办法是,采用回溯,确认要分析的部份至少包含1个完整元素。

具体做法是:判断1024字节处是否为元素结束字符 ‘>’,如果不是,则判断前一个字节,直到找到元素结束字符为止,这样可保证至少包含一个元素。

 

采用分段进行词法分析,实际每次分析的代码会不足1024字节,余下的部份汇入到下一段的分析过程即可,直到所有内容被分析完毕。

 

2.4词法分析的结果

下面是一段很简单的HTML代码。

首都在线

分析后,数据存储结构如下

<img>

<a>

text

a>

src

go.gif

width

200

height

100

href

data

首都在线


可以看到,词法分析的结果是一个元素节点链表,每个节点的属性也形成了一个链表,元素节点是有先后顺序的,元素属性的先后顺序是无所谓的。

 

词法分析将网页的文本数据流以清晰的结构表现出来,这样,在后面的应用中就可以很容易的遍历各节点,并轻松地获得各元素节点的属性。

2.5 HTML词法分析的应用

2.5.1 应用举例:

HTML词法分析程序通常应用于浏览器设计、网页制作软件设计等领域,本人以一个使用VC开发的软件“HTML智能分析”来举例说明,下载网址:

 

“HTML智能分析”同样使用Bit Token词法分析器,“HTML智能分析”是一个网页信息提取、处理软件。

 

具有以下主要功能:

1、智能提取网页中的文字信息,智能排版,并可在进行编辑后保存。

2、统计网页的有关信息。

3、根据用户设置的版式,将分析和编辑的结果,自动生成新的网页。

 

用户可使用该软件来将HTML转为TXT格式,其对HTML中文字内容的提取准确、快速、不含冗余信息,版式工整清晰,保持本来面貌。

 

其主要设计思路是,在Bit Token词法分析器的基础上,结合浏览器布局的基本算法,对影响到TXT版面效果的元素进行处理。

 

比如

标记,代表所包含的内容浏览器应不予分析,按TXT格式输出,而如表格等元素则意味着需要换行。而
在HTML中,在无
这种特殊情况时,回车都是忽略不记的。这就造成了矛盾。使用常规的简单算法进行HTML到TXT的转换无法解决
这些问题。造成转换后的版式“失真“。而“HTML智能分析”却能很好的解决。

 

由于“HTML智能分析”使用了底层的词法分析技术,还可以很容易的过滤掉标记。目前的Bit Token由于开发时间所限,未对其加以特殊处理,存在一些问题,但由于浏览器对Javascript的支持是较复杂的工作,目前的Netbit Browser尚不予实现,因而没有导致明显问题,而“HTML智能分析”这个软件只是需要对Javascript进行删除操作,也不会造成影响。尽管如 此,对

军人

眼睛

当鼠标移到文字上时,触发事件mouseover,调用ChangeImage()函数,使得图像源(SRC)发生变化,重新调入新图片。

 

由此产生两个关键问题:

1.   javascript如何获取HTML元素的名称和属性

2.   javascript如何改变HTML元素的属性,并操作WIDGET重画

 

下面分别阐述这两个问题:

首先介绍涉及到的浏览器流程:

PARSE

Tokenize

BuildModel

BuildPres

ProcessElement

WidgetPaint

 

 

 

 

 

 

 

 

 

 

 

 

 

 


问题1解决:HTML元素作为Javascript对象进行注册

注册过程在BuildModel中进行。BuildModel的首要任务是将Token后的结点按包含关系展成一棵树。其次就是要将某些结点注册为JavaScript对象。

 

注册的过程是:

定义新对象:JSObject *proto;

 

初始化该对象

TD_JSXMLElementClassInit(JS_GetGlobalContext(),

 (void **)&proto))

 

使用JS_DefineObject或JS_NewObject定义对象属性

根据是否定义了该元素的名称区别对待:

if(TD_XMLContentIsNamedItem(aElement,&aName))

{   parent = js_GetGlobalObject();

*aReturn=JS_DefineObject(JS_GetGlobalContext(),js_GetGlobalObject(),aName->mStr,&ElementClass,proto,JSPROP_ENUMERATE);

}

else

{   parent=aElement->parent->mScriptObject;

*aReturn = JS_NewObject(JS_GetGlobalContext(), &ElementClass, proto, parent);

}

将对象加入

JS_SetPrivate(JS_GetGlobalContext(), (JSObject *)*aReturn, aElement);这样,在编译时,HTML元素的标识就能被Javascript编译器识别,否则会报错变量未定义。

 

问题2解决:利用注册给对象的函数实现操作符的功能化

具体可理解为:当image0.src=”1.gif”被执行时,相当于为对象设置或改变属性,此时SetElementProperty函数被调 用(该函数在注册该对象时由JSXMLElementClassInit捆绑给该对象,其内容由用户自己定义),SetElementProperty通 过函数指针调用函数TD_JSXMLSetAtrByID,改变结点树上结点属性,并重新生成该节点对应的widget,重画界面。

 

问题3:如何建立Javascript对象与结点树上结点的对应?

解决: Javascript对象与结点树是同时生成的,它们的共同性质是结点具有相同属性,Javascript对象根据ID属性查找树,找到要操作的对应结点。

 

3.4        浏览器消息响应

在主消息循环中调用TDWidgetProcessMsg,处理与widget有关消息。

首先:取得当前焦点所在的widget

pWidget=TDWidgetGetAtPoint(pThis->baseDoc.base.mWidget,pt,&index);

处理该widget对该消息的响应。

 

最后一般为调用JavaScript执行,实现实际响应。

TDVOID  TDWidgetDoAction(TDPWidgetAction pAnchor)

{

    jsval jval;

    if(pAnchor)

        TD_EvaluateScript(JS_GetGlobalContext(),js_GetGlobalObject(),pAnchor->mAction.mStr,pAnchor->mAction.mLength,TDNULL,0,&jval);

}

其中pAnchor->mAction.mStr即为界面对象(widget)对应的JavaScript源码,解释执行的结果就是调用为该对象注册的函数来重画该widget,从而实现动态效果。

 

阅读(809) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~