Qt的XML模块包含了两种处理xml的API,分别是SAX和DOM。SAX提供了一种低层的基于事件驱动的方式解析xml文件,而DOM提供了一种高层的接口用于解析xml文件。不同之处在于DOM受制于内存的大小,一次不能解析文件大小太大的xml文件,因为它将xml文件一次性地读入内存中。
SAX方式解析XML文件
SAX方式解析XML是基于事件方式编程的。执行的流程完全取决于读入的数据。使用该方式的主要步骤是创建一个XML读取器以及一个处理器,然后将两者关联起来,之后调用parse(),涉及的各方用类图表示如下:
代码示例如下:
myhandler.h
#ifndef MYHANDLER_H
#define MYHANDLER_H
#include <QXmlDefaultHandler>
class QString;
class MyHandler : public QXmlDefaultHandler
{
public:
explicit MyHandler();
signals:
public slots:
public:
bool startDocument();
bool startElement( const QString & namespaceURI,
const QString & localName,
const QString & qName,
const QXmlAttributes & atts);
bool characters(const QString& text);
bool endElement( const QString & namespaceURI,
const QString & localName,
const QString & qName );
private:
QString indent;
};
#endif // MYHANDLER_H
myhandler.cpp
#include "myhandler.h"
#include <QObject>
#include <QTextStream>
#include <QDebug>
MyHandler::MyHandler():QXmlDefaultHandler()
{
}
bool MyHandler::startDocument() {
indent = "";
return TRUE;
}
bool MyHandler::characters(const QString& text) {
QString t = text;
qDebug() << t.remove('\n');
return TRUE;
}
bool MyHandler::startElement( const QString&,
const QString&,
const QString& qName,
const QXmlAttributes& atts) {
QString str = QString("\n%1\\%2").arg(indent).arg(qName);
qDebug() << str;
if (atts.length()>0) {
QString fieldName = atts.qName(0);
QString fieldValue = atts.value(0);
qDebug() << QString("(%2=%3)").arg(fieldName).arg(fieldValue);
}
qDebug() << "{";
indent += " ";
return TRUE;
}
bool MyHandler::endElement( const QString&,
const QString& ,
const QString& ) {
indent.remove( 0, 4 );
qDebug() << "}";
return TRUE;
}
main.cpp
#include <QApplication>
#include <QFile>
#include <QXmlInputSource>
#include "myhandler.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFile xmlFile( ":/test.xml" );
QXmlInputSource source( &xmlFile );
if (!xmlFile.open(QFile::ReadOnly | QFile::Text)) {
return -1;
}
MyHandler handler;
QXmlSimpleReader reader;
reader.setContentHandler( &handler );
if( reader.parse( source ) )
qDebug()<<"File loaded!";
return a.exec();
}
DOM方式解析XML文件
DOM方式只适合解析小的xml文件,它是基于SAX之上的一种高层解析XML方法。使用方式见如下代码所示:
#include <QtCore/QCoreApplication>
#include <QDomDocument>
#include <QFile>
#include <QDebug>
void parseFolderElement(const QDomElement &element)
{
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == "folder") {
parseFolderElement(child);
} else if (child.tagName() == "bookmark") {
QString title = child.firstChildElement("title").text();
if (title.isEmpty())
title = QObject::tr("Folder");
qDebug()<<"title="<<title;
} else if (child.tagName() == "separator") {
qDebug()<<"processing separator";
}
child = child.nextSiblingElement();
}
}
void parseXmlByDom(QIODevice *device)
{
QDomDocument domDocument;
QString errorStr;
int errorLine;
int errorColumn;
if (!domDocument.setContent(device, true, &errorStr, &errorLine,
&errorColumn)) {
qDebug()<<"Parse error at line "
<<errorLine
<<", column "
<< errorColumn
<<":\n"
<<errorStr;
return;
}
QDomElement root = domDocument.documentElement();
if (root.tagName() != "xbel") {
qDebug()<<QString( "The file is not an XBEL file.");
return;
} else if (root.hasAttribute("version")
&& root.attribute("version") != "1.0") {
qDebug()<<QString("The file is not an XBEL version 1.0 file.");
return;
}
QDomElement child = root.firstChildElement("folder");
while (!child.isNull()) {
parseFolderElement(child);
child = child.nextSiblingElement("folder");
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFile f("frank.xbel");
if( ! f.open(QIODevice::ReadOnly) )
{
qDebug()<<"failed to open file";
return -1;
}
parseXmlByDom(&f);
return a.exec();
}