简单的 C++ XML 解析器






3.56/5 (17投票s)
一个仅具有基本功能的简单 C++ XML 解析器
引言
我写这篇文章是因为我需要一个基本的 XML 解析器,并且在互联网上找不到适合我需求的解析器(一个轻量级的解析器)。
现有的解析器的复杂性相当令人望而生畏,需要大量的知识才能理解。如果你不是一个经验丰富的 C++ 程序员,很难弄懂代码,如果你是,那你可能已经写了自己的解析器。
我编写了 parse
函数,然后是一系列用于存储解析数据的类,以及一个关于如何使用它的示例(基于 MFC 对话框和树状视图)。这个解析器非常简单,只有基本的功能,没有花哨的东西。它有一些限制。
- 该解析器在一定程度上识别注释。如果 XML 文件中的任何注释出现在根节点之外,都会生成一个错误。
- 截至 2010 年 9 月 29 日,已添加了一些
CDATA
支持。它仍然是有限的(例如//<![CDATA[
将生成一个错误)。另外,CDATA
节只能作为节点值存在。如果需要,可以轻松添加额外的实现,但考虑到此项目的目的,我宁愿保持原样,以免将parse
函数复杂化到难以修改的程度。 - 不支持处理指令
- 不支持 DTD 和实体
新增功能
此项目在设计时考虑了简洁性,以便能够快速轻松地理解代码库,并添加每个特定应用程序所需的功能。
这些类只提供基本功能,因此是我能找到的所有解析器中最轻量级的:解析器(包括一些未使用的 base64
函数,如果需要可以删除)有 500 行代码,而二叉树结构有另外 500 行代码。如果需要更多功能,则需要添加这些功能以满足需求。
作为进一步开发的基础,它非常易于理解和使用。
解析函数是迭代的,它只遍历一次 XML 字符串,因此性能相当令人满意。内存需求低,每个对象只分配实际所需的内存。还有很大的改进空间,但这并非本项目的目标。
工作原理
我个人认为关于这一点不必多说,因为代码本身就能说明一切,并且它的设计易于阅读和理解。如果认为有必要,我可以详细说明它是如何工作的,以及如何进行丰富。
Using the Code
处理 XML 格式时,有三个类(用红点标记)
Cxml
、CAttribute
和 CNode
。
Cxml
类是该项目的“主力”,包含 parse 函数
bool Cxml::ParseString(_TCHAR* szXML);
解析后,需要将信息以易于使用的方式存储在内存中,因此存在 Node
和 Attribute
类。
Node
类具有类似树的结构,包含一个父指针和子节点列表。它还包含一个属性列表。
除了这些类之外,还有一组 Utils 文件(.h & .cpp),其中包含一些实用函数。
如何使用?
好的,要使用它,您需要执行以下操作
- Add
#include "Cxml.h"
到您的项目中。
- 创建一个类的实例
Cxml *oxml = new Cxml();
- 将包含 XML 代码的
string
的指针传递给parse
函数oxml->ParseString(szXML);
在 ParseString
返回后,XML 的结构将复制到类中,并且可以通过...来检索 XML 根节点。
oxml->GetRootNode();
...调用。
这里有一个特点。因为我采用了“后进先出”的方式,所以节点将以与它们在原始 XML 字符串中出现的顺序相反的顺序组织。
可以使用 Node
对象的 public
函数进行导航。但请记住,GetNextChild()
函数会增加计数器的位置,而我没有实现重置它的方法。
理解内部工作原理的最佳方法是获取演示项目并自行测试。您需要 Visual Studio 2008 来编译现有项目,而无需重建。如果您重建,请记住:它尚未经过 Unicode 测试。
下载项目并解压。编译。运行它并按加载按钮。
选择提供的 XML 文件之一。点击打开。
这是提供的其中一个 XML 文件得到的结果。
<CATALOG>
...
<PLANT>
<COMMON>Snakeroot</COMMON>
<BOTANICAL>Cimicifuga</BOTANICAL>
<ZONE>Annual</ZONE>
<LIGHT>Shade</LIGHT>
<PRICE>$5.63</PRICE>
<AVAILABILITY>071199</AVAILABILITY>
</PLANT>
<PLANT>
<COMMON>Cardinal Flower</COMMON>
<BOTANICAL>Lobelia cardinalis</BOTANICAL>
<ZONE>2</ZONE>
<LIGHT>Shade</LIGHT>
<PRICE>$3.02</PRICE>
<AVAILABILITY>022299</AVAILABILITY>
</PLANT>
</CATALOG>
历史
- 2010 年 9 月 20 日
- Added
- 2010 年 9 月 21 日
- 修订
- 2010 年 9 月 22 日
- 新版本项目已更新
- 修正了多个属性的错误
- 添加了“一些”注释支持。根节点外的注释将产生错误
- 2010 年 9 月 28 日
- 经过 Unicode 测试,并为测试添加了 Unicode XML
- 从项目中删除了智能感知文件
- 修正了 Lorenzo Gatti 发现的混淆单引号和双引号与实际分隔符的错误
- 2010 年 9 月 29 日
- 添加了对 UNICODE 字符集的运行时支持!程序必须使用此字符集编译
- 2010 年 9 月 29 日
- 已添加对
CDATA
节的一些支持 - 我还发现 Parse 函数需要一些重构,因为它变得庞大且难以理解。
- 2010 年 10 月 1 日
- 用动态分配的替换了项目中的所有固定大小的
char
数组。 - 添加了对处理指令的支持。所有处理指令现在都被视为一种特殊类型的节点,就像注释一样。
- 注释现在也可以存在于 XML 的根节点之外,因为现在最低级别的节点是
XML_DOC
节点,而不是 XML 的根节点。