一、引言
在上一篇博客里,我主要架构了一个 xml 解析器的三大模块,分别是读取模块、解析模块、获取数据模块,并在尽快实现整体架构的目标下,实现了一个非常简略的 xml 解析器。
想要了解 xml 解析器的设计流程的同学可以点击这里 XmlParser: 简易的 Xml 解析器的实现(一)。
在这一篇博客中,我将填上上一篇博客里面的坑,将读取模块里面的 xml 代码的合法性检查和解析模块里面的对于嵌套元素的解析功能一一实现。
这一篇博客虽然没有像上一篇博客里面那么大刀阔斧设计一个架构的快感,但是这两块实现(合法性检查和嵌套元素解析)都是挺复杂的逻辑,这一块可以说是一个 xml 解析器的难点所在吧。
准备好了就让我们开始吧。
二、准入检查:xml 代码的合法性检查
至于为什么要有合法性检查呢?这里我还是要多啰嗦几句:
作为一个程序员,永远要记得对于一个处理过程的输入的合法性检查保持条件发射般的敏感。只有在你的输入合乎逻辑之后,才能让你后续的处理过程不会产生匪夷所思的错误。
那么这里 xml 的合法性检查,要进行哪些检查呢?这里因为我们实现的毕竟只是一个简易的 xml 解析器,自然不能跟其他强大的库比,因此暂时就只实现以下三点检查吧:
- 尖括号
<
和>
必须搭配出现 - 反斜线
/
出现的时候 ,前面必然有一个未配对的<
,并且/
只能以</
或者/>
这两种形式出现 - 双标签对元素标签头和标签尾的名称一定要一致
那么就让我们一步一步来实现这三个条件的检查吧。
首先,尖括号 <
和 >
必须搭配出现,也就是说出现了一个 <
就必须有一个 >
封住标签,那么使用一个栈来进行检查是最简单的了。只需要遍历 xml 代码,遇到 <
压栈,遇到 >
弹出栈即可。
其次,反斜线的情况比较复杂,不过也好解决。我们在得到了一个 /
之后,首先检查它是不是 </
或者/>
这两种显示方式(分别对应了双标签对和单标签),解决这个问题可以遍历解决。另外,我们的反斜线是与标签一一对应的。那么出现了 /
则必然有一个 <
还没有得到匹配,这一点也需要记入考虑中去。
上面两条的检查代码如下:
// 检查:输入文本是否合法
// 1. 尖括号 < 和 > 必须搭配出现
// 2. 反斜线 / 出现的时候 < 必须在紧接着之前出现过
// 3. 两个标签对单词一定要一样,单标签元素无需处理
bool CWangYingXmlParser::_CheckXmlValid(std::string strXml)
{
std::stack<char> stackBracket; // 栈:尖括号
std::stack<char> stackBackSlash; // 栈:反斜线
std::stack<std::string> statckTab; // 栈:标签对
bool bBracketValid = true; // 合法:尖括号匹配
bool bBlackSlashValid = true; // 合法:反斜线
bool bIsSymmetry = true; // 合法:标签对称性
// 检查:括号匹配
for (int i = 0; i < strXml.size(); ++i) {
// --记录:当出现 < ,则直接压栈
if ('<' == strXml[i]) stackBracket.push(strXml[i]);
// --记录ÿ