SAX(Simple API for XML)为XML解析器提供了一个基于事件的标准接口。在前面讲解的DOM方法需要在一个树结构中读入和存储整个XML文档,这样会耗费大量内存,不过使用它来操作文档结构是很容易的。如果不需要对文档进行操作,而只需要读取整个XML文档,那么使用SAX方法就很高效了。SAX2接口是一种事件驱动机制,用来为用户提供文档信息。这里的事件是由解析器发出的,例如它遇到了一个开始标签或者一个结束标签等。下面来看一个例子:
<quote>A quotation.</quote>
当解析上面这行文档时会触发三个事件:
- 遇到开始标签(<quote>),这时会调用startElement()事件处理函数。
- 发现字符数据“A quotation.”,这时会调用characters()事件处理函数。
- 一个结束标签被解析(</quote>),这时会调用endElement()事件处理函数。
每当发生一个事件时,都可以在相应的事件处理函数中进行操作来完成对文档的自定义解析。比如可以在startElement()中获得元素名和属性,在characters()中获得元素中的文本,在endElement()中进行一些结束读取该元素时想要进行的操作。这些事件处理函数都可以通过继承QXmlDefaultHandler类来重新实现,Qt中提供的事件处理类如表所列,它们都是继承自QXmlDefaultHandler类的。
SAX(Simple API for XML)是用于 XML 解析器的基于事件的标准接口。XML 类的设计遵循 SAX2 Java interface,名称适合 Qt 的命名约定。对于任何会使用SAX2 的人来说,使用 Qt XML 类应该非常容易。
SAX 不同于 DOM 解析,它逐行扫描文档,一边扫描一边解析。由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中,这对于大型文档的解析是个巨大优势。
SAX读取XML原理
SAX2 接口是一种事件驱动机制,用来为用户提供文档信息。这里的事件是由解析器发出的,比如它遇到了一个开始标签或者一个结束标签等。我们只需知道,当解析器解析一个XML的元素时,就会执行相应的事件,我们只要重写这些事件处理函数,就能让它按照我们的想法进行解析。
<title>Qt</title>
解析器会依次调用如下事件处理函数:startElement(),characters(),endElement()。我们可以在startElement()中获得元素名(如“title”)和属性,在characters()中获得元素中的文本(如“Qt”),在endElement()中进行一些结束读取该元素时想要进行的操作。而所有的这些事件处理函数我们都可以通过继承QXmlDefaultHandler类来重写。
自定义MySAX类
class MySAX : public QXmlDefaultHandler
{
public:
MySAX();
~MySAX();
bool readFile(const QString &fileName);
protected:
bool startElement(const QString &namespaceURI, const QString &localName,
const QString &qName, const QXmlAttributes &atts);
bool endElement(const QString &namespaceURI, const QString &localName,
const QString &qName);
bool characters(const QString &ch);
bool fatalError(const QXmlParseException &exception);
private:
QListWidget *list;
QString currentText;
};
bool MySAX::readFile(const QString &fileName)
{
QFile file(fileName);
QXmlInputSource inputSource(&file); // 读取文件内容
QXmlSimpleReader reader;// 建立QXmlSimpleReader对象
reader.setContentHandler(this);// 设置内容处理器
reader.setErrorHandler(this);// 设置错误处理器
return reader.parse(inputSource);// 解析文件
}
// 已经解析完一个元素的起始标签
bool MySAX::startElement(const QString &namespaceURI, const QString &localName,
const QString &qName, const QXmlAttributes &atts)
{
if (qName == "library")
list->addItem(qName);
else if (qName == "book")
list->addItem(" " + qName + atts.value("id"));
return true;
}
// 已经解析完一块字符数据
bool MySAX::characters(const QString &ch)
{
currentText = ch;
return true;
}
// 已经解析完一个元素的结束标签
bool MySAX::endElement(const QString &namespaceURI, const QString &localName,
const QString &qName)
{
if (qName == "title" || qName == "author")
list->addItem(" " + qName + " : " + currentText);
return true;
}
// 错误处理
bool MySAX::fatalError(const QXmlParseException &exception)
{
qDebug() << exception.message();
return false;
}