yafeilinux 发表于 2013-5-22 13:03:33

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

使用流读写XML
版权声明该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处!

导语       从Qt 4.3开始引入了两个新的类来读取和写入XML文档:QXmlStreamReader和QXmlStreamWriter。 QXmlStreamReader类提供了一个快速的解析器通过一个简单的流API来读取格式良好的XML文档,它是作为Qt的SAX解析器的替代品的身份出现的,因为它比SAX解析器更快更方便。QXmlStreamReader可以从QIODevice或者QByteArray中读取数据。流读取器的基本原理就是将XML文档报告为一个记号(tokens)流,这一点与SAX相似,而它们的不同之处在于XML记号被报告的方式。在SAX中,应用程序必须提供处理器(回调函数)来从解析器获得所谓的XML事件;而对于QXmlStreamReader,是应用程序代码自身来驱动循环,在需要的时候可以从读取器中一个接一个的拉出记号。这个是通过调用readNext()函数实现的,它可以读取下一个记号,然后返回一个记号类型,然后可以使用isStartElement()和text()等函数来判断这个记号是否包含我们需要的信息。使用这种主动拉取记号的方式的最大的好处就是可以构建递归解析器,也就是可以在不同的函数或者类中来处理XML文档中的不同记号。

环境:Windows Xp + Qt 4.8.4+Qt Creator2.6.2

目录一、解析XML文档二、写入XML文档


正文
一、解析XML文档
1.新建Qt控制台应用,项目名称为myXmlStream,完成后将myXmlStream.pro文件的第一行代码更改为:QT       += corexml       然后保存该文件。
2.然后打开main.cpp文件,将内容更改如下:#include <QCoreApplication>
#include <QFile>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QFile file("../myXmlStream/my.xml");
    if (!file.open(QFile::ReadOnly | QFile::Text))
    {
      qDebug()<<"Error: cannot open file";
      return 1;
    }
   
    QXmlStreamReader reader;
   
    // 设置文件,这时会将流设置为初始状态
    reader.setDevice(&file);
   
    // 如果没有读到文档结尾,而且没有出现错误
    while (!reader.atEnd()) {
      // 读取下一个记号,它返回记号的类型
      QXmlStreamReader::TokenType type = reader.readNext();
      
      // 下面便根据记号的类型来进行不同的输出
      if (type == QXmlStreamReader::StartDocument)
            qDebug() << reader.documentEncoding()
                                           << reader.documentVersion();
      if (type == QXmlStreamReader::StartElement) {
            qDebug() << "<" << reader.name() << ">";
            if (reader.attributes().hasAttribute("id"))
                qDebug() << reader.attributes().value("id");
      }
      if (type == QXmlStreamReader::EndElement)
            qDebug() << "</" << reader.name() << ">";
      if (type == QXmlStreamReader::Characters
                                     && !reader.isWhitespace())
            qDebug() << reader.text();
    }
   
    // 如果读取过程中出现错误,那么输出错误信息
    if (reader.hasError()) {
      qDebug() << "error: " << reader.errorString();
    }
   
    file.close();
   
    return a.exec();
}
可以看到流读取器就是在一个循环中通过使用readNext()来不断读取记号的,这里可以对不同的记号和不同的内容进行不同的处理,既可以在本函数中进行,也可以在其他函数或者其他类中进行。可以将前面生成的my.xml文件复制到源码目录,然后运行程序,查看效果。



二、写入XML文档

与QXmlStreamReader对应的是QXmlStreamWriter,它通过一个简单的流API提供了一个XML写入器。QXmlStreamWriter的使用是十分简单的,只需要调用相应的记号的写入函数来写入相关数据即可。
将前面主函数的内容更改为:int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    QFile file("../myXmlStream/my2.xml");    if (!file.open(QFile::WriteOnly | QFile::Text))    {       qDebug() << "Error: cannot open file";       return 1;    }    QXmlStreamWriter stream(&file);    stream.setAutoFormatting(true);    stream.writeStartDocument();    stream.writeStartElement("bookmark");    stream.writeAttribute("href", "http://qt.nokia.com/");    stream.writeTextElement("title", "Qt Home");    stream.writeEndElement();    stream.writeEndDocument();    file.close();    qDebug() << "write finished!";    return a.exec();}
这里使用了setAutoFormatting(true)函数来自动设置格式,这样会自动换行和添加缩进。然后使用了writeStartDocument(),该函数会自动添加首行的XML说明(即<?xmlversion="1.0" encoding="UTF-8"?>),添加元素可以使用writeStartElement(),不过,这里要注意,一定要在元素的属性、文本等添加完成后,使用writeEndElement()来关闭前一个打开的元素。在最后使用writeEndDocument()来完成文档的写入。现在大家可以运行程序了,这时会在项目目录中生成一个XML文档。


结语数据库和XML在很多程序中都经常用到,它们的使用也总是和数据的显示联系起来,所以学习好数据库的知识也是很重要的,它们可以说是密不可分的。相关内容,大家也可以参考《Qt Creator快速入门》的相关章节以及《Qt 及Qt Quick开发实战精解》的数据管理系统的例子,里面同时应用了数据库和XML。


涉及到的源码:


上一篇: 第29篇 XML(三)Qt中的SAX

下一篇:第31篇 网络(一)Qt网络编程简介

返回:系列教程目录   

lyzyung 发表于 2014-4-21 16:12:27

楼主请问下 Qt实战那本书需要安装顺序作吗   还是可以任意章节

yafeilinux 发表于 2014-4-22 15:22:14

lyzyung 发表于 2014-4-21 16:12 static/image/common/back.gif
楼主请问下 Qt实战那本书需要安装顺序作吗   还是可以任意章节

可以任意,那个没有联系的。

wangxiangjun88 发表于 2014-5-14 16:09:35

yaifei老师我最近编写串口,数据有时候能接收有时候总是接收不了,出现
void QSerialPortPrivate::detectDefaultSettings(): Unexpected flow control settings
不知道是什么原因,您能解答下吗

yafeilinux 发表于 2014-5-20 22:39:47

wangxiangjun88 发表于 2014-5-14 16:09 static/image/common/back.gif
yaifei老师我最近编写串口,数据有时候能接收有时候总是接收不了,出现
void QSerialPortPrivate::detectDe ...

这个应该是版本问题,以前测试的时候好像也出现过这个警告。不过程序可以正常工作。

silverdemon 发表于 2016-1-22 15:06:27

这里使用了setAutoFormatting(true)函数来自动设置格式,这样会自动换行和添加缩进。然后使用了writeStartDocument(),该函数会自动添加首行的XML说明(即<?xmlversion="1.0" encoding="UTF-8"?>),添加元素可以使用writeStartElement(),不过,这里要注意,一定要在元素的属性、文本等添加完成后,使用writeTextElement()来关闭前一个打开的元素。在最后使用writeEndDocument()来完成文档的写入。现在大家可以运行程序了,这时会在项目目录中生成一个XML文档。

应该是 writeEndElement()对吧

yafeilinux 发表于 2016-1-25 17:12:41

silverdemon 发表于 2016-1-22 15:06 static/image/common/back.gif
应该是 writeEndElement()对吧

嗯。

tanghe791 发表于 2016-3-15 09:25:22

真的牛,双手赞成,谢谢了

a35566 发表于 2016-3-25 10:07:48

请教一下,用 QXmlStreamReader 这个类遍历 XML 文件,怎么保存当前的节点?
因为 readNext() 返回的是一个 tokentype 的类型,并不是节点信息,如果我在 readNext() 之后想要访问前一个节点,我需要怎么做?

yafeilinux 发表于 2016-3-25 17:36:03

a35566 发表于 2016-3-25 10:07 static/image/common/back.gif
请教一下,用 QXmlStreamReader 这个类遍历 XML 文件,怎么保存当前的节点?
因为 readNext() 返回的是一个 ...

这个是流处理,不建议用来进行单个节点操作。

a35566 发表于 2016-3-28 14:22:09

yafeilinux 发表于 2016-3-25 17:36 static/image/common/back.gif
这个是流处理,不建议用来进行单个节点操作。

如果要进行单个节点操作用 DOM 更合适么???

a35566 发表于 2016-3-28 14:25:23

另外还有个问题要请教一下,我是用 opensource 原码编译的 4.8.5,一开始 configure 里头没有添加 openssl 的支持,如果我后期要用到的话,是否只需要重新在 configure 中添加,无需整个原码重新 make ?

huihuiyu 发表于 2016-7-20 15:44:03

写得真是全面啊,有些还不好理解

liangzhenjie 发表于 2017-1-21 12:01:21

我想用xml保存软件的一些设置属性,用流操作能实现吗,比如说会更改某一个元素的属性或者text等操作

yafeilinux 发表于 2017-1-21 15:39:00

liangzhenjie 发表于 2017-1-21 12:01 static/image/common/back.gif
我想用xml保存软件的一些设置属性,用流操作能实现吗,比如说会更改某一个元素的属性或者text等操作 ...

可以。
页: [1]
查看完整版本: 第30篇 XML(四)使用流读写XML