找回密码
 立即注册
收起左侧

第29篇 XML(三)Qt中的SAX

13
回复
19655
查看
[复制链接]
累计签到:1568 天
连续签到:1 天
来源: 2013-5-21 22:27:59 显示全部楼层 |阅读模式
Qt中的SAX

版权声明

该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处!


导语

我们前面讲述了用DOM的方法对XML文档进行操作,DOM实现起来很灵活,但是这样也就使得编程变得复杂了些,而且我们前面也提到过,DOM需要预先把整个XML文档都读入内存,这样就使得它不适合处理较大的文件。下面我们讲述另一种读取XML文档的方法,即SAX 。是的,如果你只想读取并显示整个XML文档,那么SAX是很好的选择,因为它提供了比DOM更简单的接口,并且它不需要将整个XML文档一次性读入内存,这样便可以用来读取较大的文件。我们对SAX不再进行过多的介绍,因为不需要任何基础,你就可以掌握我们下面要讲的内容了。如果大家对SAX有兴趣,可以到网上查找相关资料。


环境:Windows Xp + Qt 4.8.4+QtCreator 2.6.2


目录

一、解析器解析流程
二、使用SAX读取文档


正文


一、解析器解析流程
       QtQtXml模块中提供了一个QXmlSimpleReader的类,它便是基于SAXXML解析器。这个解析器是基于事件的,但这些事件由它们自身进行关联,我们并不需要进行设置。我们只需知道,当解析器解析一个XML的元素时,就会执行相应的事件,我们只要重写这些事件处理函数,就能让它按照我们的想法进行解析。
比如要解析下面的元素:
<title>Qt</title>
解析器会依次调用如下事件处理函数:startElement(),characters(),endElement()。我们可以在startElement()中获得元素名(如“title”)和属性,在characters()中获得元素中的文本(如“Qt”),在endElement()中进行一些结束读取该元素时想要进行的操作。而所有的这些事件处理函数我们都可以通过继承QXmlDefaultHandler类来重写。


二、使用SAX读取文档


1.新建其他项目分类中的空的Qt项目,项目名称为mySAX

2.完成后向项目中添加新的C++类,类名为“MySAX”,基类填写QXmlDefaultHandler

3.然后再添加一个main.cpp文件。

4.先打开mySAX.pro文件,添加一行代码:QT+= xml,然后保存该文件。

5.打开mysax.h文件,将其内容更改为:
  1. #ifndef MYSAX_H
  2. #define MYSAX_H

  3. #include <QXmlDefaultHandler>
  4. class QListWidget;

  5. class MySAX : public QXmlDefaultHandler
  6. {
  7. public:
  8.     MySAX();
  9.     ~MySAX();
  10.     bool readFile(const QString &fileName);
  11. protected:
  12. bool startElement(const QString &namespaceURI,
  13. const QString &localName,
  14.                           const QString &qName,
  15. const QXmlAttributes &atts);
  16. bool endElement(const QString &namespaceURI,
  17. const QString &localName,
  18.                     const QString &qName);
  19.     bool characters(const QString &ch);
  20.     bool fatalError(const QXmlParseException &exception);
  21. private:
  22.     QListWidget *list;
  23.     QString currentText;
  24. };

  25. #endif // MYSAX_H
复制代码
这里主要是重新声明了QXmlDefaultHandler类的startElement()、endElement()、characters()和fatalError()几个函数,readFile()函数用来读入XML文件,QListWidget部件用来显示解析后的XML文档内容,currentText字符串变量用于暂存字符数据。

6.打开mysax.cpp文件,将其内容修改如下:
  1. #include "mysax.h"
  2. #include <QtXml>
  3. #include <QListWidget>

  4. MySAX::MySAX()
  5. {
  6.     list = new QListWidget;
  7.     list->show();
  8. }

  9. MySAX::~MySAX()
  10. {
  11.     delete list;
  12. }

  13. bool MySAX::readFile(const QString &fileName)
  14. {
  15.     QFile file(fileName);
  16.    
  17.     // 读取文件内容
  18.     QXmlInputSource inputSource(&file);
  19.    
  20.     // 建立QXmlSimpleReader对象
  21.     QXmlSimpleReader reader;
  22.    
  23.     // 设置内容处理器
  24.     reader.setContentHandler(this);
  25.    
  26.     // 设置错误处理器
  27.     reader.setErrorHandler(this);
  28.    
  29.     // 解析文件
  30.     return reader.parse(inputSource);
  31. }

  32. // 已经解析完一个元素的起始标签
  33. bool MySAX::startElement(const QString &namespaceURI,
  34. const QString &localName,
  35.                          const QString &qName,
  36. const QXmlAttributes &atts)
  37. {
  38.     if (qName == "library")
  39.         list->addItem(qName);
  40.     else if (qName == "book")
  41.         list->addItem("    " + qName + atts.value("id"));
  42.     return true;
  43. }

  44. // 已经解析完一块字符数据
  45. bool MySAX::characters(const QString &ch)
  46. {
  47.     currentText = ch;
  48.     return true;
  49. }

  50. // 已经解析完一个元素的结束标签
  51. bool MySAX::endElement(const QString &namespaceURI,
  52. const QString &localName,
  53.                        const QString &qName)
  54. {
  55.     if (qName == "title" || qName == "author")
  56.         list->addItem("        " + qName + " : " + currentText);
  57.     return true;
  58. }

  59. // 错误处理
  60. bool MySAX::fatalError(const QXmlParseException &exception)
  61. {
  62.     qDebug() << exception.message();
  63.     return false;
  64. }
复制代码
这里添加了几个函数的定义。在readFile()函数中,我们设置了文件的解析过程。Qt中提供了一个简单的XML解析器QXmlSimpleReader,它是基于SAX的。该解析器需要QXmlInputSource为其提供数据,QXmlInputSource会使用相应的编码来读取XML文档的数据。在进行解析之前,还需要使用setContentHandler()来设置事件处理器,使用setErrorHandler()来设置错误处理器,它们的参数使用了this,表明使用本类作为处理器,也就是在解析过程中出现的各种事件都会使用本类的startElement()等事件处理函数来进行处理,而出现错误时会使用本类的fatalError()函数来处理。最后,调用了parse()函数来进行解析,该函数会在解析成功时返回true,否则返回false。在后面的几个事件处理函数中,就是简单的将数据显示在QListWidget中。


7.最后打开main.cpp文件,添加如下内容:
#include "mysax.h"
#include <QApplication>
int main(int argc, char* argv[])
{   
      QApplication app(argc, argv);   
      MySAX sax;   
      sax.readFile("../mySAX/my.xml");   
      return app.exec();
}

8.将前面第27篇建立的“my.xml”文件复制到我们的源码目录中,然后运行程序,效果如下图所示。



结语

可以看到使用SAX方法来解析XML文档比使用DOM方法要清晰很多,更重要的是它的效率要高很多,不过SAX方法只适用于读取XML文档。




涉及到的源码:



上一篇:
第28篇 XML(二)使用DOM创建和操作XML文档

下一篇:第30篇 XML(四)使用流读写XML

返回:系列教程目录   


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
参与人数 1人气 +2 收起 理由
Aca + 2 对我帮助很大!

查看全部评分总评分 : 人气 +2

回复

使用道具 举报

累计签到:75 天
连续签到:1 天
2013-8-21 21:42:40 显示全部楼层
2.完成后向项目中添加新的C++类,类名为“MySAX”,基类填写QxmlDefaultHandler。

QxmlDefaultHandler  中的X 应该大写 ,提醒一下大家
难道大家 都编译无问题吗
回复 支持 反对

使用道具 举报

累计签到:1568 天
连续签到:1 天
2013-8-22 11:13:34 显示全部楼层
noway 发表于 2013-8-21 21:42
2.完成后向项目中添加新的C++类,类名为“MySAX”,基类填写QxmlDefaultHandler。

QxmlDefaultHandler  中 ...

嗯,教程以前是用Word编写的,一些字母大小写很容易自动改变。

不过在Qt Creator里面有代码自动补全,这个应该可以自动纠正的。
回复 支持 反对

使用道具 举报

累计签到:75 天
连续签到:1 天
2013-8-22 11:30:19 显示全部楼层
yafeilinux 发表于 2013-8-22 11:13
嗯,教程以前是用Word编写的,一些字母大小写很容易自动改变。

不过在Qt Creator里面有代码自动补全,这 ...

哦 ,是这样啊 。
楼主您的课程我已经快学完了 ,如果还想进一步学习,应该看那些资料与书籍,最好是一些实际的项目
因为我们公司以前的程序都用vc写,我想以后都用QT 写,QT写界面;底层的东西还用以前的c,c++代码或DLL
所以就涉及到 QT 加载 DLL,多线程,汇编等问题,不知道楼主对这方面有什么建议与指点,谢谢!
回复 支持 反对

使用道具 举报

累计签到:1568 天
连续签到:1 天
2013-8-22 17:02:56 显示全部楼层
noway 发表于 2013-8-22 11:30
哦 ,是这样啊 。
楼主您的课程我已经快学完了 ,如果还想进一步学习,应该看那些资料与书籍,最好是一些 ...

其实《入门》和《实战》两本书就是方便大家入门使用的,如果网上教程已经看完了,并且没有问题,那么可以看看《实战》,这里面的例子综合应用了很多知识点,对自己以后做项目挺有帮助的。

Qt就是C++的类库,所以跟C++兼容性很好,大部分内容都可以转到Qt上来的。
回复 支持 反对

使用道具 举报

累计签到:75 天
连续签到:1 天
2013-8-22 20:13:41 显示全部楼层
yafeilinux 发表于 2013-8-22 17:02
其实《入门》和《实战》两本书就是方便大家入门使用的,如果网上教程已经看完了,并且没有问题,那么可以 ...

好的 ,谢谢楼主,有时间读一下楼主写的那两本书,有问题再向您请教。
回复 支持 反对

使用道具 举报

累计签到:4 天
连续签到:1 天
2014-2-3 21:44:59 显示全部楼层
在弹出的运行程序,我的输出是空的
在应用程序输出窗口:
F:\C++develop\prongram\build-mySAX-桌面-Debug\debug\mySAX.exe 启动中...
"unexpected character"
是字符集的问题吗?  我改成GB2312或UTF8还是同样提示,没有任何内容
编辑环境win8+Qt 4.8.5& Qt Creator 2.8.0+MinGW-gcc440_1
回复 支持 反对

使用道具 举报

累计签到:4 天
连续签到:1 天
2014-2-3 21:50:58 显示全部楼层
WIN8  是32位的,下载源码编译也不行,同样没有任何输出, 原文要求境:Windows Xp + Qt 4.8.4+QtCreator 2.6.2         不会编译环境版本问题吧?
回复 支持 反对

使用道具 举报

累计签到:1568 天
连续签到:1 天
2014-2-7 10:13:19 显示全部楼层
ktz 发表于 2014-2-3 21:50
WIN8  是32位的,下载源码编译也不行,同样没有任何输出, 原文要求境:Windows Xp + Qt 4.8.4+QtCreator 2 ...

根据你前面提到的那些问题,估计是win 8系统的原因。
回复 支持 反对

使用道具 举报

尚未签到

2014-10-23 10:24:09 显示全部楼层
SAX的方式怎么设置支持GBK编码的XML文件?,我看代码里没有设置这一项
回复 支持 反对

使用道具 举报

累计签到:1568 天
连续签到:1 天
2014-10-30 21:54:45 显示全部楼层
oudiqianbi 发表于 2014-10-23 10:24
SAX的方式怎么设置支持GBK编码的XML文件?,我看代码里没有设置这一项

直接解析即可。
回复 支持 反对

使用道具 举报

累计签到:7 天
连续签到:1 天
2015-11-10 19:02:08 显示全部楼层
创建的控制台应用   找不到QListWidget吧  
回复 支持 反对

使用道具 举报

累计签到:1568 天
连续签到:1 天
2015-11-10 22:14:03 显示全部楼层
就这个名字 发表于 2015-11-10 19:02
创建的控制台应用   找不到QListWidget吧

恩。
回复 支持 反对

使用道具 举报

累计签到:27 天
连续签到:1 天
2016-7-21 17:12:36 显示全部楼层
窗口什么输出都没有啊~    应用程序输出如下:
/root/Qt_Study/build-mySAX-DeskTop-Debug/mySAX 启动中...
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了