您的位置:首页 > 编程语言 > Qt开发

Qt中解析xml

2014-11-20 09:31 405 查看
Qt为xml解析提供了三种不同的解析方案:

1、QXmlStreamReader,用于读取格式良好的xml文档的快速解析器;

2、DOM(文档对象模型),将xml文件转换为应用程序可以访问的树形结构;

3、SAX(xml简单应用程序编程接口),通过虚拟函数直接向应用程序报告解析事件。

比较常用的是QXmlStreamReader和DOM,QXmlStreamReader是最简单易行的方法,只需要一个类就可以搞定;DOM是将xml转换为树形结构,然后通过相关的类读取树的各个分支的数据,这种方法用到的类较多,但是功能强大,且解析类型比较多。

本文主要介绍QXmlStreamReader的使用方法,QXmlStreamReader使用简单,但是也存在缺陷,比如它就无法解析XML1.1,但这个问题很好解决。

class XmlReader
{

public:
XmlReader(QTreeWidget *treeWidget);

bool readFile(const QStringList fileList);

private:
void readFileTitle(const QString filename);
void readFirstElement(QTreeWidgetItem *parent_item);
//    读取不同分支的函数
void readDeviceInfoElement(QTreeWidgetItem *parent_item);
void readTripInfoElement(QTreeWidgetItem *parent_item);
void readDigStausElement(QTreeWidgetItem *parent_item);
void readSetValElement(QTreeWidgetItem *parent_item);
void readFaultInfoElement(QTreeWidgetItem *parent_item);
void readDataFileSizeElement(QTreeWidgetItem *parent_item);
void readFaultKeepingTimeElement(QTreeWidgetItem *parent_item);
void readFaultStartTimeElement(QTreeWidgetItem *parent_item);

//  跳过未知标签
void skipUnknownElement();

//  创建QTreeWidgetItem
QTreeWidgetItem *createChildItem(QTreeWidgetItem *parent_item=0);

QXmlStreamReader xml;
QTreeWidget *treeWidget;
};

此类是将xml解析后显示在QTreeWidget中,类可以解析多个文件。

XmlReader::XmlReader(QTreeWidget *treeWidget)

    :treeWidget(treeWidget)

{

}

bool XmlReader::readFile(const QStringList fileList)
{
if(fileList.isEmpty()){
std::cerr<<"The file list is emty!"<<std::endl;
return false;
}
int num = fileList.count();
bool isCanRead = false;
for(int i=0;i<num;i++){
QString file_str = fileList.at(i);

QFile file(file_str);
if(!file.open(QFile::ReadOnly | QFile::Text)){
std::cerr<<"Error: Cannot read file "<<qPrintable(file_str)
<<": "<<qPrintable(file.errorString())<<std::endl;

continue;
}
//将xml1.1转换为xml1.0
QString str=QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
int lineno = 0;
while (!file.atEnd())
{
if (lineno) {
str += file.readLine();
}else{//跳过第一行
file.readLine();
}
lineno++;

}
xml.clear();
//将读到的文件加入到QXmlStreamReader的输入流中
xml.addData(str);
//多个文件中只要有一个文件读取成功,isCanRead置true
isCanRead = true;
//从文件路径名中提取文件名,
QStringList dir=file_str.split("\\");
readFileTitle(dir.last());

file.close();
if(xml.hasError()){
std::cerr<<"Error: Failed to parse file "
<<qPrintable(file_str)<<": "
<<qPrintable(file.errorString())<<std::endl;
//            return false;
}else if(file.error() != QFile::NoError){
std::cerr<<"Error: Cannot read file "
<<qPrintable(file_str)<<": "
<<qPrintable(file.errorString())<<std::endl;
//            return false;
}
}

if(!isCanRead){
std::cerr<<"There is no file can read!"<<std::endl;
return false;
}

return true;
}

根据读入的文件路径找到文件并打开文件,将文件内容读入到字符串并加入到QXmlStreamReader中。

注意:由于我读入的xml文件是xml1.1格式,QXmlStreamReader无法解析,所以需要将xml文件的第一行换掉,就如程序中注释的那样。

void XmlReader::readFileTitle(const QString filename)
{

while(!xml.atEnd()){
if(xml.isStartElement()){
if(xml.name().toString() == "FaultReport"){
QTreeWidgetItem* parent = createChildItem();
parent->setText(0,QObject::tr("FaultReport"));
parent->setText(1,filename);
readFirstElement(parent);
}else{
qDebug()<<"name = "<<xml.name().toString();
qDebug()<<"The Name of element is not FaultReport";
xml.readNext();
}
}else{
xml.readNext();
}
}
}
<pre class="cpp" name="code">void XmlReader::readFirstElement(QTreeWidgetItem *parent_item)
{
xml.readNext();//跳过<FaultReport>

QTreeWidgetItem* devInfo_item = createChildItem(parent_item);
devInfo_item->setText(0,QObject::tr("DeviceInfo"));
QTreeWidgetItem* tripInfo_item = createChildItem(parent_item);
tripInfo_item->setText(0,QObject::tr("TripInfo"));
QTreeWidgetItem* digStatus_item = createChildItem(parent_item);
digStatus_item->setText(0,QObject::tr("DigitalStatus"));
QTreeWidgetItem* setValue_item = createChildItem(parent_item);
setValue_item->setText(0,QObject::tr("SettingValue"));
QTreeWidgetItem* faultInfo_item = createChildItem(parent_item);
faultInfo_item->setText(0,QObject::tr("FaultInfo"));
QTreeWidgetItem* dataFileSize_item = createChildItem(parent_item);
dataFileSize_item->setText(0,QObject::tr("DataFileSize"));
QTreeWidgetItem* faultKeepingTime_item = createChildItem(parent_item);
faultKeepingTime_item->setText(0,QObject::tr("FaultKeepingTime"));
QTreeWidgetItem* FaultStartTime_item = createChildItem(parent_item);
FaultStartTime_item->setText(0,QObject::tr("FaultStartTime"));

while(!xml.atEnd()){
if(xml.isEndElement()){//</FaultReport>
xml.readNext();
break;
}

if(xml.isStartElement()){
if(xml.name().toString() == "DeviceInfo"){
readDeviceInfoElement(devInfo_item);
}else if(xml.name().toString() == "TripInfo"){
readTripInfoElement(tripInfo_item);
}else if(xml.name().toString() == "DigitalStatus"){
readDigStausElement(digStatus_item);
}else if(xml.name().toString() == "SettingValue"){
readSetValElement(setValue_item);
}else if(xml.name().toString() == "FaultInfo"){
readFaultInfoElement(faultInfo_item);
}else if(xml.name().toString() == "DataFileSize"){
readDataFileSizeElement(dataFileSize_item);
}else if(xml.name().toString() == "FaultKeepingTime"){
readFaultKeepingTimeElement(faultKeepingTime_item);
}else if(xml.name().toString() == "FaultStartTime"){
readFaultStartTimeElement(FaultStartTime_item);
}else{
skipUnknownElement();
}
}else{
xml.readNext();
}
}
}


上述两个函数就是对xml进行解析,这里有一个注意点,就是xml.name()返回的是QStringRef,需要转化为QString才能和字符串进行比较。

<p>void XmlReader::readDeviceInfoElement(QTreeWidgetItem *parent_item)
{
    QString name_str,val_str;
    xml.readNext();</p><p>    QTreeWidgetItem* devChild = createChildItem(parent_item);</p><p>    while(!xml.atEnd())
    {
        if(xml.isEndElement()){// '/DeviceInfo'
            xml.readNext();
            break;
        }</p><p>        if(xml.isStartElement()){
            if(xml.name().toString() == "name"){
//                xml.readNext();
                name_str = xml.readElementText()
4000
;</p><p>                devChild->setText(0,name_str);</p><p>                if(xml.isEndElement()){
                    xml.readNext();
                }
            }else if(xml.name().toString() == "value"){
                val_str = xml.readElementText();</p><p>                devChild->setText(1,val_str);</p><p>                if(xml.isEndElement()){
                    xml.readNext();
                }
            }else{
                skipUnknownElement();
            }
        }else{
   xml.readNext();
  }
    }
    qDebug()<<"read one device info";
}</p>
其他几个函数都是类似的编程结构,在此就不一一提供了,最后看一下显示效果吧
<img src="https://img-blog.csdn.net/20141120104239812?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmV3eWhlcg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ qt xml