公司电子商务网站建设规划方案,网站建设与管理就业前景,鄂州网站制作人才招聘,罗湖网站设计多少钱QXmlStreamReaderQXmlStreamReader类通过简单的流式API为我们提供了一种快速的读取xml文件的方式。他比Qt自己使用的SAX解析方式还要快。所谓的流式读取即将一个xml文档读取成一系列标记的流#xff0c;类似于SAX。而QXmlStreamReader类和SAX的主要区别就是解析这些标记的方式…QXmlStreamReaderQXmlStreamReader类通过简单的流式API为我们提供了一种快速的读取xml文件的方式。他比Qt自己使用的SAX解析方式还要快。所谓的流式读取即将一个xml文档读取成一系列标记的流类似于SAX。而QXmlStreamReader类和SAX的主要区别就是解析这些标记的方式。使用SAX解析时应用程序必须提供一些处理器回调函数来处理来自解析器的一系列的所谓的xml事件不同的xml标记会触发不同的事件从而进行相应的处理。而使用QXmlStreamReader应用程序自己可以驱动整个循环从解析器中一个接一个的拉取出xml标记。这个动作可以通过readNext()来完成该函数会读取出下一个完整的标记然后其tokenType()。然后我们就可以使用一系列方便的函数如isStartElement()text等来确定或得到具体所读取的内容。这种拉模式pull的解析方法的好处就在于我们可以将对一个xml文档的解析分开到多个函数中来完成对不同的标记使用一个单独的函数来处理。QXmlStreamReader类的典型使用方法如下 QXmlStreamReader xml;...while (!xml.atEnd()) {xml.readNext();... // do processing}if (xml.hasError()) {... // do error handling}如果在解析的过程中出现了错误atEnd()和hasError()会返回trueerror会返回所出现的具体错误类型。errorString()lineNumbercolumnNumber和characterOffset函数可以用来得到错误的具体信息一般我们使用这几个函数来构建一个错误字符串来提示用户具体的错误信息。同时为了简化应用程序代码QXmlStreamReader还提供了一个raiseError()的机制可以让我们在必要时触发一个自定义的错误信息。QXmlStreamReader是一个增量式的解析器。它可以处理文档不能被一下处理完的情况比如该xml文件来自于多个文件或来自于网络。当QXmlStreamReader解析完所有的数据但该xml文档是不完整的这时它会返回一个PrematureEndOfDocumentError类型的错误。然后当有更多的数据到来时它会从这个错误中恢复然后继续调用readNext()来解析新的数据。QXmlStreamReader是不太消耗内存的因为它不会在内存中存储整个xml文档树仅仅存储当前它所解析的标记。此外QXmlStreamReader使用QStringRef来解析所有的字符串数据而不是真实的QString对象这可以避免不必要的小字符串内存分配代价。QStringRef是对QString或其子串的一个简单包装并提供了一些类似于QString类的API但它不会进行内存的分配并在底层使用了引用计数来共享数据。我们可以在需要时调用QStringRef的toString()来得到一个真实的QString对象。读xml文件example.xml?xml version1.0 encodingUTF-8?
labels mapdemo1 ver1.0 label id1802232 x1568/x y666/y /label label id1802230 x1111/x y622/y /label
/labels#ifndef XMLREAGER_H
#define XMLREAGER_H
#include QXmlStreamReaderclass xmlreader
{
public:xmlreader();bool readFile(const QString fileName);private:void readlabelsElement(); //读取label标签void readlabelElement(); //读取label标签void readxElement(); //读取x标签void readyElement(); //读取y标签void skipUnknownElement(); //跳过未知标签QXmlStreamReader reader;
};#endif // XMLREAGER_H#include xmlreader.h
#include iostream
#include QDebug
#include QFilexmlreader::xmlreader()
{}bool xmlreader::readFile(const QString fileName)
{//以只读和文本方式打开文件如果打开失败输出错误日志并且返回false QFile file(fileName);if (!file.open(QFile::ReadOnly | QFile::Text)) {std::cerr Error: Cannot read file qPrintable(fileName) : qPrintable(file.errorString()) std::endl;return false;}//将文件设置成xml阅读器的输入设备reader.setDevice(file);reader.readNext(); //直接读取下一个节点因为首先读到的标签是XML文件的头部第一行while (!reader.atEnd()) //外部循环未到文件结尾就一直循环读取{if (reader.isStartElement()) //外部分支如果不是起始标签则直接读取下一个节点{if (reader.name() labels) //内部分支如果根节点不是 labels//说明读取的文件是错误的{qDebug() reader.name();//通过qDebug()输出当前节点的名字这里输出labelsreadlabelsElement(); //读取labels节点的内容} else { //raiseError函数用来自定义输出错误日志的内容这里输出Not a labels filereader.raiseError(QObject::tr(Not a labels file));}} else {reader.readNext();}}//关闭文件如果读取发生错误hasError()或者文件有错误输出错误信息返回false,file.close();if (reader.hasError()) {std::cerr Error: Failed to parse file qPrintable(fileName) : qPrintable(reader.errorString()) std::endl;return false;} else if (file.error() ! QFile::NoError) {std::cerr Error: Cannot read file qPrintable(fileName) : qPrintable(file.errorString()) std::endl;return false;}return true;
}void xmlreader::readlabelsElement()
{reader.readNext();//读取了根节点labels后继续读取下一个节点while (!reader.atEnd()) {if (reader.isEndElement()){reader.readNext();break; //如果是结束节点则结束循环//循环执行下去读到的第一个结束节点是/labels,而不是/label//这是执行readlabelElement()函数中得到的结果当读到/label时//该函数跳出循环并读取下一个节点而下一个节点是label或者/labels}if (reader.isStartElement()) {if (reader.name() label) { //获得label的attributes()值也就是id,转换成字符串输出qDebug() reader.attributes().value(id).toString();qDebug() reader.name();readlabelElement();} else {skipUnknownElement();//未知节点直接跳过}}else{reader.readNext();}}
}void xmlreader::readlabelElement()
{reader.readNext();while (!reader.atEnd()) {if (reader.isEndElement()) {reader.readNext();break;}if (reader.isStartElement()) {if (reader.name() x) {readxElement();} else if (reader.name() y) {readyElement();} else {skipUnknownElement();}} else {reader.readNext();}}
}void xmlreader::readxElement()
{QString x reader.readElementText();qDebug() x: x;if (reader.isEndElement())reader.readNext();}
void xmlreager::readyElement()
{QString y reader.readElementText();//执行这个函数以后y获得了坐标值并且当前节点//自动变成结束节点/yqDebug() y: y;if (reader.isEndElement())reader.readNext(); //在这里读取下一个节点就是/label}
//是一个递归函数
void xmlreader::skipUnknownElement()
{reader.readNext();while (!reader.atEnd()) {if (reader.isEndElement()) {reader.readNext();break;}if (reader.isStartElement()) {skipUnknownElement();//函数的递归调用} else {reader.readNext();}}
}#include QtCore/QCoreApplication
#include xmlreader.h
#include iostreamint main(int argc, char *argv[])
{QCoreApplication a(argc, argv);xmlreader reader;reader.readFile(labels.xml);return a.exec();
}读取结果如下图所示 teachers.xml其中学校school三楼floor3的老师信息还有一个学生的信息。6个老师1个学生?xml version1.0 ?
schoolfloor3 id3 time2019/10/11teacherentry nameJobage30/agesportsoccer/sport/entryentry nameTomage32/agesportswimming/sport/entry/teacherteacherentry nameJob2age30/agesportsoccer/sport/entryentry nameTomage32/agesportswimming/sport/entry/teacherteacherentry nameJob3age30/agesportsoccer/sport/entryentry nameTomage32/agesportswimming/sport/entry/teacherteacherentry nameJob4age30/agesportsoccer/sport/entryentry nameTomage32/agesportswimming/sport/entry/teacherteacherentry nameJob5age30/agesportsoccer/sport/entryentry nameTomage32/agesportswimming/sport/entry/teacherstudententry nameLilyage20/agesportdancing/sport/entryentry nameKeithage21/agesportrunning/sport/entry/studentteacherentry nameJob6age30/agesportsoccer/sport/entryentry nameTomage32/agesportswimming/sport/entry/teacher/floor3
/school注意重点在函数中的代码移植出来可以使用。记得将“用来计数”的变量进行整理。还有文件所在地址也要更换。将XML的文件内容首先读取到一个变量中再分析这个变量的内容。受XML文件的编码格式影响很大如果有中文乱码的现象出现要慎重使用这种方法可能无法读取。#include QtCore/QCoreApplication
#include QXmlStreamReader
#include QFile
#include iostreamvoid ReadXml()
{//用来计数int teacherCount 0;int ageCount 0;int sanlouCount 0;int schoolCount 0;//读取文件QString fileName D:/JBXML/teachers.xml;QFile file(fileName);if (!file.open(QFile::ReadOnly | QFile::Text)){return ;}//QXmlStreamReader操作任何QIODevice.QXmlStreamReader xml(file);//解析XML直到结束while (!xml.atEnd() !xml.hasError()){//读取下一个element.QXmlStreamReader::TokenType token xml.readNext();/*以下内容用于分析读取的内容可以将每一个读取到的标签名字打印出来*//*if (token QXmlStreamReader::Invalid){//如果有读取错误将被打印出来std::cout xml.errorString().toStdString();}std::cout xml.tokenString().toStdString() \t;std::cout xml.name().toString().toStdString() std::endl;*//*显示这个分析过程你会看到很清晰的读取过程*///如果获取的仅为StartDocument,则进行下一个if (token QXmlStreamReader::StartDocument){continue;}//如果获取了StartElement,则尝试读取if (token QXmlStreamReader::StartElement){//如果为person则对其进行解析if (xml.name() teacher){teacherCount;}if (xml.name() age){ageCount;}if (xml.name() floor3){sanlouCount;}if (xml.name() school){schoolCount;}}}if (xml.hasError()){//QMessageBox::information(NULL, QString(parseXML), xml.errorString());}file.close();std::cout teacherCount teacher std::endl;std::cout ageCount ages std::endl;std::cout sanlouCount 3rdFloors std::endl;std::cout schoolCount schools std::endl;
}
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);ReadXml();return a.exec();
}可以得到XML文件中各个标签tag 即尖括号内的信息然后进行判断。如果是“teacher”会计数然后可以看到总共有6个老师。运行结果如下图所示如果把中间注释的代码打开可以看到每一个读取到的标签并将读取过程打印出来。运行结果如下图所示