HTML 阅读器 C++ 类库






4.82/5 (80投票s)
2004 年 3 月 30 日
12分钟阅读

346264

7084
一个基于推送模型解析的轻量级、快速、简单、低开销的 C++ 类库。
目录
引言
在搜索一个允许从内存字符串缓冲区或物理磁盘文件中读取 HTML 文本的类库失败后,我决定迫切需要这样一个库。例如,有很多 XML (可扩展标记语言) 解析器可用,如 SAX (Simple API for XML),它们允许您通过处理读取器在解析给定 XML 文档的特定符号时生成的事件来简单地解析 XML。
受 XML 的 SAX 解析器的启发,我决定从头开始自己开发一个 HTML 阅读器 C++ 类库,它提供了一个简单、轻量级、快速,最重要的是,一个低开销的解决方案来处理 HTML 文档。与 SAX 一样,我决定开发一个基于事件的解析器,它在遇到文档中的各种元素时会引发事件。基于事件的解析器的优点是读取器读取 HTML 文档的一个部分,生成一个事件,然后移至下一部分。它占用的内存更少,更适合处理大型文档。
基于事件的解析器
基于事件的解析器使用回调机制来报告解析事件。这些回调碰巧是您将要覆盖的受保护的虚拟成员函数。诸如元素开始标签或结束标签的检测等事件将触发对您类的相应成员函数的调用。应用程序实现一个事件处理程序并将其注册到读取器。由应用程序负责在设计的事件处理程序中编写代码来实现应用程序的目标。基于事件的解析器提供了一个简单、快速、更低级别的文档访问。
基于事件的解析器不创建源文档的内存表示。它们只是解析文档,并沿途通知客户端应用程序找到的各种元素。接下来发生什么由客户端应用程序负责。基于事件的解析器不缓存信息,并且具有令人羡慕的极小的内存占用。
文件
要在您的 MFC 应用程序项目中 M使用 HTML 阅读器类库,您需要将一些文件添加到您的项目中
头文件 | 源文件 | 类 |
LiteHTMLReader.h | LiteHTMLReader.cpp | CLiteHTMLReader |
LiteHTMLTag.h | - | CLiteHTMLTag |
LiteHTMLAttributes.h | - | CLiteHTMLAttributes |
LiteHTMLAttributes.h | LiteHTMLAttributes.cpp | CLiteHTMLElemAttr |
LiteHTMLEntityResolver.h | LiteHTMLEntityResolver.cpp | CLiteHTMLEntityResolver |
注意: LiteHTMLCommon.h
也必须包含在您的项目中。
类的简要说明
CLiteHTMLReader
是我们库的主要类,它与其他CLiteHTML*
类协同工作来解析给定的 HTML 文档。它包含 (Read
和ReadFile
) 方法来启动解析过程,该过程可以处理内存字符串缓冲区或物理磁盘文件。CLiteHTMLReader
允许您捕获读取器在文档中找到各种元素(如标签开始、标签结束、HTML 注释等)时生成的事件。但是为了处理这些事件,您的应用程序必须定义一个实现ILiteHTMLReaderEvents
接口的类,该接口在LiteHTMLReader.h
文件中声明。CLiteHTMLTag
类顾名思义,与 HTML 标签相关。它处理从给定字符串中解析和存储标签信息,例如标签的名称以及标签的属性/特性。它提供了一个方法 (实际上,所有上述类都提供了一个名为parseFromStr
的方法),当文档被解析时,CLiteHTMLReader
类的Read
和ReadFile
方法会调用它。通常,CLiteHTMLTag
不直接由您的应用程序使用。如上所述,它与读取器协同工作,帮助解析 HTML 标签。CLiteHTMLElemAttr
和CLiteHTMLAttributes
类是相互关联的,因为CLiteHTMLAttributes
提供了一种基于集合的机制来保存CLiteHTMLElemAttr
对象的数组,这些对象可以通过属性名称或零基索引值进行访问。与CLiteHTMLTag
类一样,这些类通常也不直接由您的应用程序使用。- 最后一个是
CLiteHTMLEntityResolver
类,它有助于解析实体引用。实体引用是 HTML 文档中可能包含的字符的数字或符号名称。它们对于引用很少使用的字符,或作者工具难以或不可能输入的字符很有用。实体引用以 "&" 符号开头,以分号 (;) 结尾。一些常见的例子是:<
代表 < 符号,>
代表 > 符号,等等。
从上面的讨论中,有一点很清楚,那就是 CLiteHTMLTag
、CLiteHTMLAttributes
和 CLiteHTMLElemAttr
类提供了一个名为 parseFromStr
的方法,CLiteHTMLReader
在读取 HTML 文档时使用该方法来进一步委托解析过程。
用法
好的,现在让我们开始学习如何在 MFC 项目中使用这个库
- 第一步很简单。您所要做的就是将所有文件 (在上面的 文件 部分给出) 添加到您的项目中。
- 第二步,虽然是可选的,是创建一个实现
ILiteHTMLReaderEvents
接口的类。ILiteHTMLReaderEvents
实际上是一个抽象类,它充当一个接口,所有需要处理CLiteHTMLReader
类引发的事件的类都必须实现它。例如,#include "stdafx.h" #include "LiteHTMLReader.h" class CEventHandler : public ILiteHTMLReaderEvents { private: void BeginParse(DWORD dwAppData, bool &bAbort); void StartTag(CLiteHTMLTag *pTag, DWORD dwAppData, bool &bAbort); void EndTag(CLiteHTMLTag *pTag, DWORD dwAppData, bool &bAbort); void Characters(const CString &rText, DWORD dwAppData, bool &bAbort); void Comment(const CString &rComment, DWORD dwAppData, bool &bAbort); void EndParse(DWORD dwAppData, bool bIsAborted); };
您必须注意到我上面使用的“可选”一词。原因在于,如果您不提供自己的事件处理程序实现,ILiteHTMLReaderEvents
类会提供一个默认实现,该实现什么也不做。要了解有关ILiteHTMLReaderEvents
接口的更多信息,请跳转到本文的 ILiteHTMLReaderEvents 描述 部分。 - 第三步是创建
CLiteHTMLReader
类的实例,如下所示CLiteHTMLReader theReader;
- 现在我们应该调用
CLiteHTMLReader
类的Read
或ReadFile
方法了吗???
不!在我们将事件处理程序注册到读取器之前,我们的事件处理程序实现将不会开始接收通知,方法是调用CLiteHTMLReader
类的setEventHandler
方法。因此,假设我们实现ILiteHTMLReaderEvents
接口的类的名称是CEventHandler
,第四步是创建CEventHandler
的实例,并调用setEventHandler
,将该实例变量的地址传递给它。CEventHandler theEventHandler; theReader.setEventHandler(&theEventHandler);
现在,对于所有正在思考是否可以将NULL
指针传递给setEventHandler
方法的人来说,答案是肯定的,而且可以随时传递。更不用说,您也可以通过调用setEventHandler
并传递另一个实例的地址来随时更改事件处理程序。 - 现在,第五步也是最后一步,是在步骤 3 中创建的
CLiteHTMLReader
实例变量上调用Read
或ReadFile
方法,并传递适当的参数,即如果您决定解析内存字符串缓冲区,则调用Read
方法并传递要解析的字符串的地址。如果您需要从磁盘文件解析 HTML 文档,您可以调用ReadFile
方法,该方法类似于Read
,但接受文件句柄 (HANDLE
) 而不是指向字符数组的指针。看一个例子TCHAR strToParse[] = _T("<HTML>" "<HEAD>" "<TITLE>" "<!-- title goes here -->" "</TITLE>" "</HEAD>" "<BODY LEFTMARGIN="15px">This is a sample HTML document.</BODY>" "</HTML>"); theReader.Read(strToParse);
或者CFile fileToParse; if (fileToParse.Open(_T("test.html"), CFile::modeRead)) { theReader.ReadFile(fileToParse.m_hFile); fileToParse.Close(); }
关于事件处理的更多信息
ILiteHTMLReaderEvents
类提供了一个接口,所有想要处理 CLiteHTMLReader
在解析 HTML 文档时发送的通知的类都必须实现该接口。ILiteHTMLReaderEvents
处理程序的事件顺序由被解析文档中的信息顺序决定。需要注意的是,该接口包含一系列方法,CLiteHTMLReader
在解析操作期间会调用这些方法。读取器会将适当的信息传递给方法的参数。要对某个方法执行某种处理,只需在您自己的 ILiteHTMLReaderEvents
实现中向该方法添加代码即可。
ILiteHTMLReaderEvents
类中定义的所有方法的通用参数,除了 EndParse
,包括
dwAppData
:一个 32 位应用程序特定数据。bAbort
:您可以根据应用程序的需求将此参数设置为true
或false
,以指定读取器是否应继续解析缓冲区中的其余数据,或者在当前事件处理程序完成处理后立即中止。
EndParse
方法接收 bIsAborted
参数而不是 bAbort
,它指示 EndParse
是否由于正常解析终止而发生。
除了上述参数外,所有方法(除了 BeginParse
和 EndParse
)都接收一些额外信息(特定于事件),这些信息由读取器在解析 HTML 文档时检索。例如,当解析 HTML 标签(开始或结束)时,StartTag
或 EndTag
方法接收指向 CLiteHTMLTag
的指针,该指针包含标签的名称以及标签的属性(如果有)。属性信息仅在解析的标签是开始标签时检索,因为结束标签不能包含任何属性/值对。如果 CLiteHTMLTag
没有关联的属性信息,则指针变量包含 NULL
。因此,EndTag
方法总是接收一个 NULL
指针是显而易见的。应用程序的责任(也是一个好的编程实践)是在使用它之前检查 NULL
指针。
类似地,该类的 Comment
和 Characters
方法接收一个对包含提取文本的 CString
的引用。Comment
方法接收 rComment
参数,该参数包含注释文本(不包括分隔符),即不包含 <!--
和 -->
。Characters
方法接收一个 rText
参数,该参数表示元素的内容或读取器无法解析的某些文本。
类视图
CLiteHTMLReader 类成员
成员 描述 CLiteHTMLReader()
构造一个 CLiteHTMLReader
对象。EventMaskEnum setEventMask(DWORD);
设置一个新的事件掩码。 EventMaskEnum setEventMask(DWORD, DWORD);
通过添加和/或删除标志来更改当前事件掩码。 EventMaskEnum getEventMask(void) const;
返回先前通过调用 setEventMask
设置的事件掩码。DWORD setAppData(DWORD);
设置要传递给事件处理程序的应用程序特定数据。 DWORD getAppData(void) const;
返回先前通过调用 setAppData
设置的应用程序特定数据。ILiteHTMLReaderEvents* setEventHandler(ILiteHTMLReaderEvents*);
向读取器注册一个事件处理程序。 ILiteHTMLReaderEvents* getEventHandler(void) const;
返回当前关联的事件处理程序。 UINT Read(LPCTSTR);
从指定字符串解析 HTML 文档。 UINT Read(HANDLE);
从文件解析 HTML 文档,给定其 HANDLE。 CLiteHTMLTag 类成员
成员 描述 CLiteHTMLTag()
构造一个 CLiteHTMLTag
对象。CLiteHTMLTag(CLiteHTMLTag&, bool)
从现有实例构造一个 CLiteHTMLTag
对象。第一个参数是源CLiteHTMLTag
的引用,第二个参数决定是进行复制还是接管封装的CLiteHTMLAttributes
指针。~CLiteHTMLTag()
销毁一个 CLiteHTMLTag
对象。CString getTagName(void) const;
返回标签的名称。 const CLiteHTMLAttributes* getAttributes(void) const;
返回与此 CLiteHTMLTag
关联的属性集合的指针。UINT parseFromStr(LPCTSTR, bool&, bool&, bool);
从第一个参数指定的字符串解析 HTML 标签。第二个和第三个参数接收一个布尔值 true/false,分别表示解析的标签是开始标签和/或结束标签。第四个参数指定是否也解析标签的属性。 CLiteHTMLAttributes 类成员
成员 描述 CLiteHTMLAttributes()
构造一个 CLiteHTMLAttributes
对象。CLiteHTMLAttributes(CLiteHTMLAttributes&, bool)
从现有实例构造一个 CLiteHTMLAttributes
对象。第一个参数是源CLiteHTMLAttributes
的引用,第二个参数决定是进行复制还是接管封装的指针。~CLiteHTMLAttributes()
销毁一个 CLiteHTMLAttributes
对象。int getCount() const;
返回 CLiteHTMLElemAttr
项的计数。int getIndexFromName(LPCTSTR) const;
给定属性名查找属性的索引。 CLiteHTMLElemAttr operator[](int) const;
给定属性索引返回一个 CLiteHTMLElemAttr
对象。CLiteHTMLElemAttr getAttribute(int) const;
给定属性索引返回一个 CLiteHTMLElemAttr
对象。CLiteHTMLElemAttr operator[](LPCTSTR) const;
给定属性名返回一个 CLiteHTMLElemAttr
对象。CLiteHTMLElemAttr getAttribute(LPCTSTR) const;
给定属性名返回一个 CLiteHTMLElemAttr
对象。CString getName(int) const;
给定属性索引返回属性的名称。 CString getValue(int) const;
给定属性索引返回值。 CString getValueFromName(LPCTSTR) const;
给定属性名返回值。 CLiteHTMLElemAttr* addAttribute(LPCTSTR, LPCTSTR);
向集合添加一个新的 CLiteHTMLElemAttr
项。bool removeAttribute(int);
从集合中删除一个 CLiteHTMLElemAttr
项。bool removeAll(void);
从集合中删除所有 CLiteHTMLElemAttr
项。UINT parseFromStr(LPCTSTR);
从给定字符串解析属性/值对。 CLiteHTMLElemAttr 类成员
成员 描述 CString getName(void) const;
返回 CLiteHTMLElemAttr
的名称。CString getValue(void) const;
返回 CLiteHTMLElemAttr
的值。bool isColorValue(void) const;
确定属性值是否包含颜色引用。 bool isNamedColorValue(void) const;
确定属性值是否为命名颜色值。 bool isSysColorValue(void) const;
确定属性值是否为命名系统颜色值。 bool isHexColorValue(void) const;
确定属性值是否为十六进制格式的颜色值。 bool isPercentValue(void) const;
检查属性是否包含百分比值。 COLORREF getColorValue(void) const;
返回属性的颜色值。 CString getColorHexValue(void) const;
以十六进制格式返回属性的 RGB 值。 unsigned short getPercentValue() const;
返回属性的百分比值。 short getLengthValue(LengthUnitsEnum&) const;
返回属性的长度值。 operator bool() const;
将属性值转换为 bool
。operator BYTE() const;
将属性值转换为 BYTE
(unsigned char
)。operator double() const;
将属性值转换为 double
。operator short() const;
将属性值转换为 signed short int
。operator LPCTSTR() const;
返回属性的值。 UINT parseFromStr(LPCTSTR);
从给定字符串解析属性/值对。
许可证
此代码可以以任何您想要的方式(包括商业用途)以编译形式使用。代码可以被重新分发而未经销售,前提是未经作者书面同意,并且此通知以及作者姓名和所有版权声明保持不变。但是,未经作者书面许可,不得将此文件和附带的源代码托管在网站或公告板上。
本软件按“原样”提供,不附带明示或暗示的保证。作者对本产品可能造成的任何损害/业务损失不承担任何责任。请自行承担风险使用!