QT开发(四十四)——流方法解析XML

QT开发(四十四)——流方法解析XML

一、流方法解析XML简介

QT 4.3开始,QT引入了两个新的类来读取和写入XML文档:QXmlStreamReader和QXmlStreamWriter。

QXmlStreamReader类提供了一个快速的解析器通过一个简单的流API来读取良构的XML文档,是作为QT的SAX解析器的替代者出现的,比SAX解析器更快更方便。    QXmlStreamReader可以从QIODevice或QByteArray中读取数据。QXmlStreamReader以一种快速的基于流的方式访问良格式XML文档,特别适合于实现一次解析器(所谓“一次解析器”,即只需读取文档一次,然后像一个遍历器从头到尾一次性处理XML文档,期间不会有反复的情况,只能顺序访问标签)。

QXmlStreamReader使用了递增式的解析器,适合于在整个XML文档中查找给定的标签、读入无法放入内存的大文件以及处理XML的自定义数据。每次QXmlStreamReader的readNext()函数调用,解析器都会读取下一个标记,按照返回的标记类型进行处理。

QXmlStreamWriter类提供了简单流接口的XML写入器,写入XML文档只需要调用相应的标记写入函数来写入相关数据。

二、QXmlStreamReader

1、QXmlStreamReader简介

QXmlStreamReader提供了一个通过流接口读取良构XML文档的快速解析器。QXmlStreamReader比QT自身的SAX解析器更快、更方便。在某些情况下,作为在应用程序中使用QXmlStreamReader解析器比使用DOM树要更快、更方便。QXmlStreamReader可以从QIODevice或者QByteArray中读取数据。

与SAX解析器相似,流读取器的基本原理是将XML文档报告为一个标记(tokens)流。QXmlStreamReader与SAX主要的不同在于这些XML标记如何被报告。对于SAX来说,应用程序必须提供处理器来从解析器获得XML事件;对于QXmlStreamReader来说,应用程序代码自身驱动循环,在需要的时候从读取器中一个一个地拉出标记。这是通过调用readNext()函数完成的。readNext()函数中,读取器从输入流中读取下一个标记,然后返回标记类型。isStartElement()和text()等函数用来检查这个标记获取我们已经读取的标记的信息。这种拉取标记方式的最大好处就是可以构建递归继承解析器,这意味着可以很容易将你的XML解析代码分成不同的函数方法或类。

QXmlStreamReader经典的循环如下:

QXmlStreamReader xml;

...

while (!xml.atEnd()) {

xml.readNext();

... // do processing

}

if (xml.hasError()) {

... // do error handling

}

QXmlStreamReader使用了递增式的解析器,适合于在整个XML文档中查找给定的标签、读入无法放入内存的大文件以及处理XML的自定义数据。每次QXmlStreamReader的readNext()函数调用,解析器都会读取下一个标记,按照返回的元素类型进行处理。

QXmlStreamReader是不包括外部实体的良构XML 1.0解析器。只要没有错误发生,应用程序代码就能确保流读取器提供的数据满足W3C的良构XML文档标准。例如,你能肯定所有标签真正地被嵌套和恰当关闭,引用到使用正确替换文本替换的内部实体中,并且属性已经被规范化或是根据内部DTD子集增加。

当解析时,如果错误发生,atEnd()和hasError() 会返回true, error()函数返回发生的错误。errorString()、lineNumber()、columnNumber()和characterOffset() 函数会构造适当的错误或警告信息。为了简化应用程序代码,QXmlStreamReader包含发送错误信号的机制,发送错误机制可以发送由相同的错误处理函数处理的自定义错误。

QXmlStream理解和解析命名空间,namespaceUri()函数返回元素所在的命名空间,name()函数返回元素的本地名字。命名空间和名字的结合唯一标识了一个元素。

QXmlStreamReader是一个递增解析器,能够处理由于文档分块到达而不能够立即解析文档全部内容的情况。在整个我能当被解析完成前,当读取器超出了文档数据范围时,读取器会报告一个PrematureEndOfDocumentError错误。当更多的数据到达时,无论是调用了addData()函数还是网络设备有了更多可用的数据,读取器将从PrematureEndOfDocumentError错误中恢复,继续解析readNext()的新数据。

例如,如果你的应用程序从网络中读取数据,你会发一个网络请求到管理者并接收返回的网络应答。由于QNetworkReply是一个IO设备,你要连接QNetworkReply的readyRead() 信号到自定义的槽函数。在槽函数中,你可以使用readAll读取所有的可用数据,使用addData()函数传递数据到XML流读取器。到时调用自定义的从读取器中读取XML事件的解析函数。

由于不存储整个文档树在内存中,QXmlStreamReader设计的比较节省内存。

2、QXmlStreamReader成员函数

void QXmlStreamReader::addData(const QByteArray &data)

void QXmlStreamReader::addData(const QString &data)

void QXmlStreamReader::addData(const char *data)

给读取器增加更多的数据读取,如果读取器没有设备,什么也不做

bool QXmlStreamReader::atEnd() const

如果读取器读取到了XML文档结束或是发生错误导致读取中止时,返回true

QXmlStreamAttributes QXmlStreamReader::attributes() const

返回开始元素的属性

void QXmlStreamReader::clear()

从读取器中删除任何设备或数据,重置内部状态为初始状态

QIODevice *QXmlStreamReader::device() const

返回和读取器关联的当前设备,没有则返回0

Error QXmlStreamReader::error() const

返回当前错误的类型

bool QXmlStreamReader::hasError() const

如果有错误发生,返回true

TokenType QXmlStreamReader::readNext()

读取下一个标记,返回它的类型

void QXmlStreamReader::setDevice(QIODevice *device)

设置读取器的当前设备到device

TokenType QXmlStreamReader::tokenType() const

返回当前标记的类型

QStringRef QXmlStreamReader::documentEncoding() const

如果标记类型是StartDocument,返回XML声明中指定的编码字符串

QStringRef QXmlStreamReader::documentVersion() const

如果标记类型是StartDocument,返回XML声明中指定的版本字符串

QStringRef QXmlStreamReader::name() const

返回一个StartElement、EndElement或是EntityReference的本地名字

bool QXmlStreamReader::isWhitespace() const

如果读取器报告字符串只由空格组成,返回true

bool QXmlStreamReader::isStartElement() const

如果标记类型是StartElement,返回true

bool QXmlStreamReader::isStartDocument() const

如果标记类型是StartDocument,返回true

bool QXmlStreamReader::isEndDocument() const

如果标记类型是EndDocument,返回true

bool QXmlStreamReader::isEndElement() const

如果标记类型是EndElement,返回true

3、QXmlStreamReader实例

#include <QCoreApplication>
#include <QFile>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QFile file("test.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();
}

三、QXmlStreamWriter

1、QXmlStreamWriter简介

QXmlStreamWriter类提供了简单流接口的XML写入器。

QXmlStreamWriter操作由setDevice()函数指定的IO设备,API函数简单而直接:对于要写入的每个XML标记或事件,写入器都提供了具体的函数。

2、QXmlStreamWriter成员函数

bool QXmlStreamWriter::autoFormatting() const

如果自动格式化功能打开,返回true

QTextCodec *QXmlStreamWriter::codec() const

返回当前赋值给流的编码方式

QIODevice *QXmlStreamWriter::device() const

返回关联QXmlStreamWriter的当前设备,如果没有,返回0

bool QXmlStreamWriter::hasError() const

如果流写入到底层设备失败,返回true

void QXmlStreamWriter::setAutoFormatting(bool enable)

如果enable为true,打开自动格式化功能

void QXmlStreamWriter::setCodec(QTextCodec *codec)

设置流的编码为codec

void QXmlStreamWriter::setCodec(const char *codecName)

设置流的编码为codeName的编码

void QXmlStreamWriter::setDevice(QIODevice *device)

设置当前设备到device,如果流要写入到QByteArray,可以创建一个QBuffer设备

void QXmlStreamWriter::writeAttribute(const QString &namespaceUri, const QString &name, const QString &value)

写入名为name,值为vlaue的属性到命名空间namespaceUri

void QXmlStreamWriter::writeAttribute(const QString &qualifiedName, const QString &value)

写入一个名为qualifiedName,值为value的属性

void QXmlStreamWriter::writeAttribute(const QXmlStreamAttribute &attribute)

写入一个属性attribute

void QXmlStreamWriter::writeAttributes(const QXmlStreamAttributes &attributes)

写入属性向量attributes

void QXmlStreamWriter::writeTextElement(const QString &namespaceUri, const QString &name, const QString &text)

写入一个名为name的文本元素到namespaceUri命名空间,内容为text

void QXmlStreamWriter::writeTextElement(const QString &qualifiedName, const QString &text)

写入一个名为qualifiedName,文本为text的文本元素

void QXmlStreamWriter::writeStartElement(const QString &namespaceUri, const QString &name)

写入一个命名空间为namespaceUri,名为name的开始元素

void QXmlStreamWriter::writeStartElement(const QString &qualifiedName)

写入qualifiedName的开始元素

void QXmlStreamWriter::writeStartDocument(const QString &version)

void QXmlStreamWriter::writeStartDocument()

void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalone)

void QXmlStreamWriter::writeProcessingInstruction(const QString &target, const QString &data = QString())

写入一个target和data的处理指令

void QXmlStreamWriter::writeEndElement()

关闭前一个开始元素

void QXmlStreamWriter::writeEndDocument()

关闭所有打开的开始元素,换行

void QXmlStreamWriter::writeCharacters(const QString &text)

写入文本

3、QXmlStreamWriter实例

QXmlStreamWriter的使用只需要调用相应的标记写入函数来写入相关数据。

#include <QCoreApplication>
#include <QFile>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QFile file("test.xml");
    if (!file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate))
    {
        qDebug() << "Error: cannot open file";
        return 1;
    }
    QXmlStreamWriter stream(&file);
    stream.setAutoFormatting(true);
    //写入StartDocument
    stream.writeStartDocument();
//写入StartElement
    stream.writeStartElement("bookmark");
    //写入标签属性
    stream.writeAttribute("href", "http://qt.nokia.com/");
    //写入文本元素
    stream.writeTextElement("title", "Qt Home");
    //写入EndElement
    stream.writeEndElement();
    //写入EndDocument
    stream.writeEndDocument();
    file.close();
    qDebug() << "write finished!";
 
    return a.exec();
}
时间: 2024-12-22 05:29:48

QT开发(四十四)——流方法解析XML的相关文章

QT开发(十四)——QT绘图系统

QT开发(十四)--QT绘图系统 一.QT绘图原理 Qt4中的2D绘图系统称为Arthur绘图系统,可以使用相同的API在屏幕上和绘图设备上进行绘制,主要基于QPainter.QPainterDevice和 QPainterEngine.QPainter执行绘图操作,QPainterDevice提供绘图设备,是一个二维空间的抽象,QPainterEngine提供一些接口.QPainter用来执行具体的绘图相关操作,如画点,画线,填充,变换,alpha通道等.QPaintDevice类是能够进行绘

QT开发(四十三)——SAX方式解析XML

QT开发(四十三)--SAX方式解析XML 一.SAX简介 SAX是Simple API for XML的简写,是一种解析XML文件的替代方法,不是由W3C官方所提出的标准,是一种事件驱动的XML API,接近于底层,速度较快,但不便于随机访问任意节点. SAX解析的核心是事件处理机制,具有占用内存少,效率高等特点. SAX采用事件机制的方式来解析XML文档.使用SAX解析器对XML文档进行解析时,SAX解析器根本不创建任何对象,只是在遇到XML文档的各种标签如文档开始.元素开始.文本.元素结束

从零开始学ios开发(十四):Navigation Controllers and Table Views(上)

这一篇我们将学习一个新的控件Navigation Controller,很多时候Navigation Controller是和Table View紧密结合在一起的,因此在学习Navigation Controller的同时,我们还将继续学习Table View其他一些特性,毕竟Navigation Controller还是相对来说毕竟简单的,没有什么太大的花头,它的主要作用就是一个view的切换,切来切去,而Table View的花头就比较多了,这次我们将这2个控件结合在一起进行学习. 再多说一

S3C2416裸机开发系列十四_GCC下UCGUI的移植(2)

S3C2416裸机开发系列十四 GCC下UCGUI的移植(2) 象棋小子    1048272975 现在主要讲解一下在GCC移植UCGUI,Makefile工程如何加入目录,加入源码,c标准库,编译选项的设置. 笔者的Makefile模板提取自uboot,工程中加入目录,加入源码都是很简单的,详细的介绍请参考前面章节" GCC启动代码工程应用实例".下面主要介绍UCGUI目录下很多的源码文件Makefile的编写,一种可行的方式就是把GUI目录上所有的c文件,不管有无用到,均加入工程

Go语言开发(十四)、Go语言常用标准库四

Go语言开发(十四).Go语言常用标准库四 一.heap 1.heap简介 heap仅仅提供了最小堆的操作,没有提供堆的数据结构,堆的数据结构必须由开发者自己实现.heap提供了一个heap.Interface接口来作为堆的操作和堆的数据结构(开发者自己实现)之间的桥梁,堆的数据结构必须满足此接口: type Interface interface { sort.Interface Push(x interface{}) // add x as element Len() Pop() inter

嵌入式Linux裸机开发(十四)——ADC

嵌入式Linux裸机开发(十四)--ADC 一.AD转换简介 AD转换就是模数转换,就是把模拟信号转换成数字信号.A/D转换器是用来通过一定的电路将模拟量转变为数字量.模拟量可以是电压.电流等电信号,也可以是压力.温度.湿度.位移.声音等非电信号.在A/D转换前,输入到A/D转换器的输入信号必须经各种传感器把各种物理量转换成电压信号.A/D转换后,输出的数字信号可以有8位.10位.12位.14位和16位等. 二.ADC控制器 ADC控制器时钟: 时钟源为PCLK_PSYS,经过一次分频后得到AD

S3C2416裸机开发系列十四_GCC下UCGUI的移植(1)

S3C2416裸机开发系列十四 GCC下UCGUI的移植(1) 象棋小子    1048272975 GUI(图形用户界面)极大地方便了非专业用户的使用,用户无需记忆大量的命令,取而代之的是可以通过窗口.菜单.按键等方式进行操作.在某些场合,设计一款人机界面丰富友好的嵌入式产品能赢得更多的用户.笔者此处就s3c2416基于UCGUI图形用户界面的使用作一个简单的介绍. 1. 代码准备 UCGUI 3.98源码,这个版本的UCGUI是开放源码的最高版本,之后版本只提供库文件,不再开源.笔者以UCG

QT开发(十六)——QT绘图实例-钟表

QT开发(十六)--QT绘图实例-钟表 一.钟表实现原理 钟表的实现需要设置定时器,定时器每隔一秒发送timeout()信号到QWidget::update()槽函数,update()槽函数将会重绘一次窗口,重写重绘事件函数paintEvent(QPaintEvent *event),根据获取的当前系统时间的时钟.分钟.秒钟重绘钟表的时针.分针.秒针. QTimer *timer = new QTimer(this); timer->start(1000);//一秒钟 connect(timer

QT开发(十九)——QT内存泄漏问题

QT开发(十九)--QT内存泄漏问题 一.QT对象间的父子关系 QT最基础和核心的类是:QObject,QObject内部有一个list,会保存children,还有一个指针保存parent,当自己析构时,会自己从parent列表中删除并且析构所有的children. QT对象之间可以存在父子关系,每一个对象都可以保存它所有子对象的指针,每一个对象都有一个指向其父对象的指针. 当指定QT对象的父对象时,父对象会在子对象链表中加入该对象的指针,该对象会保存指向其父对象的指针. 当QT对象被销毁时,