一、基本介绍
1 老版的Qt提供了两种访问XML文件的方式:DOM和SAX。
2 DOM 方式:将 XML 文档转换为树形结构存储到内存中,再进行读取,消耗的内存比较多。此外,由于文档都已经存储到内存,所以需要频繁实现修改等操作时,使用起来比较方便。
3 SAX 方式:相比于 DOM,SAX 是一种速度更快,更有效的方法,它逐行扫描文档,一边扫描一边解析(由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中,这对于大型文档的解析是个巨大优势)。而且相比于 DOM,SAX 可以在解析文档的任意时刻停止解析。但操作复杂,很难修改 XML 数据。
自QT4.3版本开始,QT提供了两个新类来读写XML:QXmlStreamReader 和 QXmlStreamWriter。读写方式可类比于SAX。目前QT已经停止对DOM和SAX的维护与更新。
4 QXmlStreamWriter 类提供了一个使用简单的流 API,用于写入 XML,与之相对应的是 QXmlStreamReader(读取 XML)。
5 QXmlStreamReader类支持对XML读取的操作。对于 XML 的内容,通常情况下,我们只关心 XML 元素的解析。这时,可以通过 QXmlStreamReader 中的便利函数 readNextStartElement() 来实现。
实例
1案例介绍:读取qt运行当前目录下所有文件,通过类QXmlStreamWriter将其按照xml格式对文件进行写操作,并将xml文件保存在当前目录。通过类QXmlStreamReader读取生成的xml文件,并输出。(注意需要.pro文件中添加 xml 如 QT += xml)
生成的XML文件内容为:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<文件列表>
<目录 Dirname="E:/myTest/myXml/build-myXml-Desktop_Qt_5_9_1_MinGW_32bit-Debug">
<文件名>.qmake.stash</文件名>
<文件名>debug</文件名>
<文件名>fileList.xml</文件名>
<文件名>Makefile</文件名>
<文件名>Makefile.Debug</文件名>
<文件名>Makefile.Release</文件名>
<文件名>release</文件名>
<文件名>ui_widget.h</文件名>
</目录>
</文件列表>
对XML文件不了解,
相关头文件:
#include <QXmlStreamAttributes>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
XML写存函数:
QDir *dir=new QDir(".");
void writeFile(){
QFileInfoList infoList = dir->entryInfoList();
infoList.removeFirst();
infoList.removeFirst();
QString strFile("fileList.xml");
QFile file(strFile);
if (!file.open(QFile::WriteOnly | QFile::Text)) { // 只写模式打开文件
qDebug() << QString("Cannot write file %1(%2).").arg(strFile).arg(file.errorString());
return;
}
QXmlStreamWriter writer(&file);
writer.setCodec("UTF-8"); // XML 编码
writer.setAutoFormatting(true); // 自动格式化
writer.writeStartDocument("1.0", true); // 开始文档(XML 声明)
writer.writeStartElement("文件列表"); // 开始根元素 <Blogs>
writer.writeStartElement("目录"); // 开始子元素 <Blog>
QString DirName = dir->currentPath();
writer.writeAttribute("Dirname", DirName); // 属性
foreach (QFileInfo info, infoList) {
QString fileName = info.fileName();
writer.writeTextElement("文件名", fileName);
}
writer.writeEndElement(); // 结束子元素 </Blog>
writer.writeEndElement(); // 结束根元素 </Blogs>
writer.writeEndDocument(); // 结束文档
file.close();
}
XML读取函数:
void readFile(){
QString strFile("fileList.xml");
QFile file(strFile);
if (!file.open(QFile::ReadOnly | QFile::Text)) { // 只写模式打开文件
qDebug() << QString("Cannot write file %1(%2).").arg(strFile).arg(file.errorString());
return;
}
QXmlStreamReader reader(&file);
while(!reader.atEnd()){
QXmlStreamReader::TokenType nType = reader.readNext();
if( nType == QXmlStreamReader::StartElement ){
QString nameStr = reader.name().toString();
QXmlStreamAttributes Attributes = reader.attributes();
if(Attributes.hasAttribute("Dirname")){
qDebug()<<Attributes.value("Dirname").toString();
}
if(QString::compare(nameStr,QStringLiteral("文件名")) == 0) {
reader.readNext();
qDebug() << QStringLiteral("文件名:%1").arg(reader.text().toString());
// qDebug() << QStringLiteral("文件名:%1").arg(reader.readElementText()); //该语句等效于上面两条语句
}
}
}
}
读取的文件格式:
"E:/myTest/myXml/build-myXml-Desktop_Qt_5_9_1_MinGW_32bit-Debug"
"文件名:.qmake.stash"
"文件名:debug"
"文件名:fileList.xml"
"文件名:Makefile"
"文件名:Makefile.Debug"
"文件名:Makefile.Release"
"文件名:release"
"文件名:ui_widget.h"
参考对比分析xml的写存:
安装基本例子,设置 writer.setCodec("UTF-8"); // XML 编码
writer.setAutoFormatting(true); // 自动格式化
writer.writeStartDocument("1.0", true); // 开始文档(XML 声明)
应该不会出现中文乱码,否则可能出现中文乱码,建议不使用中文。
XML(1) XML(2)
XML(3)
总结:writeEmptyElement();是一个空节点,里面不存在其他节点,因此结尾是/>,writeEmptyElement()相当于在:
writer->writeStartElement("po");
writer->writeEndElement();
两句中不插入任何节点,因此为空节点,空节点也可以添加属性值,空节点的结尾和其他节点的结尾不同,以/>结尾。
writer->writeTextElement("name", "ssssssssssssss");不是空节点,是文本节点,具有正常的结尾。
QString::compare(reader.name().toString(),QStringLiteral("文件名")) == 0
reader.text()
writer->writeStartElement("po");
writer->writeEndElement();
都是成对出现的;
XML(1) 代码:
bool Annotation::toXML(QXmlStreamWriter* writer) const {
if (!writer)
return false;
QString number;
writer->writeStartElement("annotation");
if (!_comments.isEmpty())
writer->writeAttribute("comments", _comments);
if (_positionSet) {
writer->writeEmptyElement("position");
writer->writeAttribute("x", number.setNum(_position[0]));
writer->writeAttribute("y", number.setNum(_position[1]));
writer->writeAttribute("z", number.setNum(_position[2]));
writer->writeEmptyElement("po");
}
writer->writeStartElement("mulu");
writer->writeTextElement("name", "ssssssssssssss");
writer->writeEndElement();
writer->writeEndElement(); //annotation
if (writer->hasError())
return false;
return true;
}
XML(2) 代码:
bool Annotation::toXML(QXmlStreamWriter* writer) const {
if (!writer)
return false;
QString number;
writer->writeStartElement("annotation");
if (!_comments.isEmpty())
writer->writeAttribute("comments", _comments);
if (_positionSet) {
writer->writeStartElement("position");
writer->writeAttribute("x", number.setNum(_position[0]));
writer->writeAttribute("y", number.setNum(_position[1]));
writer->writeAttribute("z", number.setNum(_position[2]));
writer->writeStartElement("po");
writer->writeEndElement();
writer->writeEndElement(); //annotation
}
writer->writeStartElement("mulu");
writer->writeTextElement("name", "ssssssssssssss");
writer->writeEndElement();
writer->writeEndElement(); //annotation
if (writer->hasError())
return false;
return true;
}
XML(3) 代码:
bool Annotation::toXML(QXmlStreamWriter* writer) const {
if (!writer)
return false;
QString number;
writer->writeStartElement("annotation");
if (!_comments.isEmpty())
writer->writeAttribute("comments", _comments);
if (_positionSet) {
writer->writeStartElement("position");
writer->writeAttribute("x", number.setNum(_position[0]));
writer->writeAttribute("y", number.setNum(_position[1]));
writer->writeAttribute("z", number.setNum(_position[2]));
writer->writeEndElement(); //annotation
}
writer->writeStartElement("mulu");
writer->writeTextElement("name", "ssssssssssssss");
writer->writeEndElement();
writer->writeEndElement(); //annotation
if (writer->hasError())
return false;
return true;
参考对比分析xml的读取:
基本介绍中的读取:
总结:读取writeTextElement("name", "ssssssssssssss"),则需要使用 reader.readNext()读取到name后再读取一次,或者直接使用reader.readElementText()进度读取
if(QString::compare(nameStr,QStringLiteral("文件名")) == 0) {
reader.readNext();
qDebug() << QStringLiteral("文件名:%1").arg(reader.text().toString());
// qDebug() << QStringLiteral("文件名:%1").arg(reader.readElementText()); //该语句等效于上面两条语句
}
基本介绍中使用:reader.readNext()循环读取。
while (!reader->atEnd()) {
QXmlStreamReader::TokenType nType = reader->readNext();
if (nType == QXmlStreamReader::StartElement) {
QString nameStr = reader->name().toString();
qDebug() << "test"<<nameStr;
}
}
新的读取方法,使用 reader.readNextStartElement(),reader.readElementText(), reader->readNext()混合进行读取:
需要先调用:
reader.readNextStartElement();
不然读取不到数据。
bool Annotation::fromXML(QXmlStreamReader* reader) {
if (!reader || "annotation" != reader->name()) {
return false;
}
QXmlStreamAttributes attr;
attr = reader->attributes();
if (attr.hasAttribute("comments")) {
setComments(attr.value("comments").toString());
}
do {
reader->readNext();
} while (reader->isWhitespace());
//reader.readNextStartElement();//可以代替do while语句
if (reader->isStartElement() && "position" == reader->name()) {
attr = reader->attributes();
if (!attr.hasAttribute("x") || !attr.hasAttribute("y") || !attr.hasAttribute("z")) {
qWarning() << Q_FUNC_INFO << "Position missing x, y, or z.";
return false;
}
setPosition(attr.value("x").toString().toDouble(), attr.value("y").toString().toDouble(),
attr.value("z").toString().toDouble());
reader->readNext();
if (!(reader->isEndElement() && "position" == reader->name())) {
qWarning() << Q_FUNC_INFO << "Format error";
return false;
}
do {
reader->readNext();
} while (reader->isWhitespace());
}
if (!(reader->isEndElement() && "annotation" == reader->name())) {
qWarning() << Q_FUNC_INFO << "Format error";
return false;
}
if (reader->hasError()) {
qWarning() << Q_FUNC_INFO << "Reader error";
return false;
}
return true;
}
三、QXmlStreamReader,QXmlStreamWriter 可写入Qstring或者文件
文件读写:
QFile tempFile("annotation_file.xml");
tempFile.open(QFile::WriteOnly | QFile::Text | QIODevice::Truncate);
QXmlStreamWriter writer(&tempFile);
write.....
tempFile.close();
QFile tempFile("annotation_file.xml");
tempFile.open(QFile::ReadOnly | QFile::Text | QIODevice::Truncate);
QXmlStreamReader reader(&tempFile);
read....
tempFile.close();
if (tempFile.exists())
{
tempFile.remove();
}
Qstring读写:
QString xml;
QXmlStreamWriter writer(&xml);
write.....
QXmlStreamReader reader(xml);
read.....