事件驱动:Parse-Handler模型(如:xml之SAX模型)
该模型主要有Parser和Handler两个组件。其原型大体如下:
class
xxxHandler
{
public
:
//
any event sended from Parser
...
};
class
xxxParser
{
public
:
xxxxParser(InputSource
*
source);
HRESULT parse(xxxxHandler
*
handler)
{
//
analyze source and send event to handler
...
}
};
该模型不规定Handler类型的详细规格,由Parser的实现者根据具体情况而定。
这种模型的核心思想就是由Parser类来具体分析文本的格式,而让信息真正的处理者Handler类从具体的格式中脱离出来,不再需要关心文本物理组织细节。
Tokenizer模型(如:编译器的词法分析器)
这种模型仅涉及一个Tokenizer组件。该组件负责将文本分解为一个个token。其原型大体如下:
class
xxxTokenizer
{
public
:
xxxTokenizer(InputSource
*
source);
//
//
成功返回S_OK,如果遇到eof返回S_FALSE。
//
HRESULT next(TOKEN
*
token);
};
其中分析的结果以一个结构体TOKEN表示。这个结构体如何设计,同样视具体情况而定。通常它看起来是这样的:
struct
TOKEN
{
UINT type;
union
{
DATATYPE1 data1;
//
当type = type1时
DATATYPE2 data2;
//
当type = type2时
...
};
};
有了Tokenizer,我们就可以轻易的遍历整个文档:
void
visit(InputSource
*
source)
{
TOKEN token;
xxxTokenizer tokenizer(source);
while
(tokenizer.next(
&
token)
==
S_OK)
{
print(token);
}
}
token应当如何划分,其粒度如何,完全取决于设计者的考量。以以下一段xml文本为例:
<elem attr="value">content</elem>
你可以划分为:
<
elem
//
element start
attr
=
"
value
"
//
attr-value pair
content
//
content
</
elem
>
//
element end
也可以将attr-value pair细分为三个token:attr, assign-symbol, value。
你甚至也可以将整个element作为一个token。
从广义上来说,我们文件系统提供的字节流本身已经是一个Tokenizer了,只不过它划分的token是一个个并无多少逻辑含义的character。
而我们后面提到的DOM模型,也可以算是一个Tokenizer。只不过它划分的token只有一个,就是DOM树,与文件系统的字节流走的是另一个极端。
Tokenizer方式与Parse-Handler方式设计思路,最大的不同在于具体处理信息的人主被动地位相异。在Tokenizer模式下,信息处理者调用Tokenizer得到分析数据,如果相邻的token存在上下文关系,你可以根据需要去取得下一个token,故处于主动地位。
而Parse-Handler模式相关死板一些,一方面Handler类实现者才是真正试图处理信息的人,但是实际上对信息的划分(token)却是由Parse规定的,未必完全符合Handler类的需求。另一方面在token存在上下文关系,当前接受的数据信息不足时,Handler类无法随心所欲的取得下一个token(因为从流程上它是被动的数据接受方),而只能暂时缓存数据,等待下一条信息的到来。
文档对象:DOM模型
DOM模型是最高级的一种模型。它的思路是将文档完整地读入内存,并提供数据访问接口。
DOM模型消耗的内存最多,可提供的服务(我们可以联想一下xml的诸多应用,如xslt等)也最为完整。
这里提到DOM模型消耗的内存最多,这种说法并不全面。例如,在将它与Parse-Handler模型相比时,我们只是计算了Parser的开销,而Handler类是客户实现的,内存开销多少,无从计算。
另一方面,由于DOM模型可以按自己的方式组织数据,它在内存开销上的可优化余地很大,并且客户在使用它时通常不再需要大量的内存分配操作;而Parse-Handler模型中,Handler类的实现者出现蹩脚的设计可能性非常高,计入Handler类的内存开销的话,有时甚至可能远远超过采用DOM模型。
因此我个人认为相对于DOM的能力而言,内存问题在DOM模型中并不算一个了不起的缺陷。实现者可以有很多技巧来进行内存优化。
但是DOM模型有一个问题,就是它一开始就将文档完整的读入了内存,使得它无法胜任那些对响应时间要求较高、希望能够渐进处理的应用。而这一点是采用Parse-Handler模型和Tokenizer模型的好处。
后记
这篇文章写得比较早,因为最近写
WINX可视化开发工具
相关的设计稿时用到,所以整理了下。我个人在文本文件和各种文档格式的文件打交道较多,多年来也算是形成了一定的经验。我个人现在越来越倾向于采用DOM模型来处理文件。原因在于采用DOM模型有很多优点:
- DOM模型是提供了最高级的服务,模块的客户负担少。
- 模块划分极其清晰,方便维护。通常DOM模型的内部仍然建立于SAX模型(或Tokenizer模型)上,但是这种依赖局限在DOM模型的内部。因此,程序通常会划分为3层:
SAX(或Tokenizer) ==> DOM模型 ==> DOMClient(实际的应用)
- 内存管理方面的可优化余地大。在多数情况下,我们建立的DOM模型是只读的(或允许进行少量修改),这种情形下,内存管理方案可以以最简洁的方式实现。下文我们详细讨论这一点。在此之前,我推荐你回顾一下《
C++内存管理变革:最袖珍的垃圾回收器
》。
- 易获得更好的性能。虽然理论上来讲程序建立在SAX模型性能上可以获得更好的性能,但是经验表明,在团代开发的情形下,采用DOM模型的性能通常可优于建立在SAX模型之上的同样功能的复杂程序(不是简单打印或提取有限数据的情形)。
相关推荐
### 程序设计模式实例分析 #### 备忘录模式 (Memento Pattern) ##### 模式定义 备忘录模式是一种行为设计模式,它能在不破坏封装的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态。这样之后就可以将该...
《基于微博的爬虫与文本分析系统》是一个典型的毕业设计项目,主要涵盖了网络爬虫技术和文本分析技术在社交媒体数据处理中的应用。这个项目的核心在于如何有效地获取微博数据,然后对这些数据进行深入的分析,以揭示...
设计模式是软件工程中的宝贵经验总结,它是一种在特定场景下解决问题的标准解决方案。在Android开发中,设计模式的应用能够提升代码的可读性、可维护性和复用性。本书涵盖了多种常见的设计模式,如单例模式、工厂...
总结,这个C语言编写的文本编辑器是一个典型的系统级应用实例,它展示了C语言在实现复杂功能时的灵活性和效率。通过分析源代码和设计报告,我们可以深入学习到C语言编程、文件操作、内存管理、用户交互设计等多个...
在软件设计模式的世界里,`Command`(命令)和`Facade`(外观)模式是非常重要的两种设计模式。它们分别服务于不同的目的,但都是为了提高代码的可读性、可维护性和灵活性。 `Command`模式是一种行为设计模式,它将...
本书的一大亮点是提供了大量可用于多种模式分析任务的MATLAB代码,包括生物信息学、文本分析和图像分析等领域。这不仅有助于实践者快速上手,实施解决方案,也为研究者提供了丰富的实验素材和理论验证的机会。 ### ...
许多代码采用 MATLAB 编写,适用于生物信息学、文本分析和图像分析等多个领域的模式分析任务。 2. **理论与实践入门**:对于学生和研究人员而言,本书提供了对基于核的模式分析领域的快速入门指南。书中通过实例...
在IT领域,文本处理是一项重要的任务,特别是在大数据分析、信息检索和自然语言处理中。"根据关键词提取文本"是一个典型的文本处理应用场景,它涉及到文件操作、字符串匹配和数据存储等多个技术点。在这个项目中,...
虽然提供的部分内容并未给出具体的设计实例,但我们可以基于常见的iPhone应用界面来探讨一些典型设计实践: 1. **导航栏设计**: - 导航栏位于屏幕顶部,通常包含返回按钮、页面标题和右上角的操作按钮等元素。 -...
- **MVC(模型-视图-控制器)**:文本编辑器可能采用了这一设计模式,将数据模型、用户界面和控制逻辑分离,提高代码的可维护性和可扩展性。 6. **版本控制**: - 作为一个经常更新的项目,很可能使用了Git进行...
总的来说,基于C语言子集的词法分析器设计是一个典型的编译原理实践项目,它要求我们理解正则表达式、状态机模型以及如何处理文本输入。通过这个项目,不仅可以掌握编译器的基本组件,还能提升问题解决和编程能力。
一个好的分词算法对于后续的文本分析有着决定性的影响。分词的准确度和效率会直接影响到自然语言处理系统的性能。 论文中提到的算法具有语言无关性的特点,这表明该算法不仅适用于汉语,还能够适应其他语言的分词...
小镇的空间形态分析、交通发展策略以及功能策划等要素综合考虑了生态、人文和科技创新三个方面的要素,确保了小镇的可持续性发展。 产业发展 产业篇详细介绍了云产业的定义、产业发展的基础和模式,以及产业发展的...
Java过滤器是Java编程中一种常见的设计模式,主要用于处理数据流或请求。它们通常被用在网络应用、文件系统操作和文本处理等场景中,允许开发者通过一系列预定义的规则来拦截、修改或转发数据。在Java中,Servlet ...
【毕业设计Demo】基于NLP方法的keyinfo提取的文本内容图示器是一个典型的自然语言处理(NLP)项目,其目标是通过先进的NLP技术从文本中抽取出关键信息,并以图形化的方式进行展示。这个项目对于理解和掌握NLP的基础...
书中不仅提供了实际可用的算法、核函数以及解决方案,而且特别针对生物信息学、文本分析和图像分析等领域的模式分析任务,提供了大量的Matlab代码实现。对于学生和研究人员而言,本书也提供了易于理解的核方法入门...