目录
三、使用QDomDocument类读写Xml文档另外一种写法
一、利用Qt读写Xml文件的方式
QDomDocument类:Qt的QDom模块提供了一个基于DOM的API,使用QDomDocument类可以方便地读取和操作XML文件。该类提供了DOM树结构的操作方法,可以实现XML的解析和生成等功能。优点是易于使用和修改XML文档,缺点是相对较慢,尤其是处理大型XML文档时。
QXmlStreamReader和QXmlStreamWriter类:Qt的QXml模块提供了一种基于流的解析方法,使用QXmlStreamReader类可以有效地解析XML文件,而使用QXmlStreamWriter类可以方便地生成XML文件。这种方式具有较低的内存消耗和较快的解析速度,适用于处理大型XML文件。
QXmlSimpleReader和QXmlDefaultHandler类:Qt还提供了一种基于事件的解析方式,使用QXmlSimpleReader类可以将XML文件解析为一系列的事件,然后使用QXmlDefaultHandler类重写事件处理方法,实现自定义的XML解析逻辑。这种方式具有较低的内存消耗和较快的解析速度,适用于处理大型XML文件,但需要编写相对复杂的处理逻辑
二、使用QDomDocument类读写Xml文档
写XML文档:
#include<iostream>
#include <QDomComment>
#include <QFile>
#include <QTextStream>
using namespace std;
int main()
{
//1、新建文件
QFile file("/home/dwq/Desktop/xxx.xml");
if(!file.open(QIODevice::WriteOnly))
{
return -1;
}
//2、新建DoM树
QDomDocument doc;
//3、添加说明信息
QString insData=QString("version=\"1.0\" encoding=\"gb23121\"");
QDomProcessingInstruction ins=doc.createProcessingInstruction("xml",insData); //将文档声明添加到DOM树
doc.appendChild(ins);
//4、添加节点信息
//4.1、添加根结点class
QDomElement root=doc.createElement("class");
doc.appendChild(root);
//4.2、添加第一个Student结点
QDomElement student1=doc.createElement("student"); //为student结点添加sex、age属性
QDomAttr attr1=doc.createAttribute("sex");
attr1.setNodeValue("男");
student1.setAttributeNode(attr1);
attr1 = doc.createAttribute("age");
attr1.setNodeValue("18");
student1.setAttributeNode(attr1);
//为Student结点添加子节点id name
QDomElement kidEle = doc.createElement("id");
kidEle.appendChild(doc.createTextNode("01"));
student1.appendChild(kidEle);
kidEle = doc.createElement("name");
kidEle.appendChild(doc.createTextNode("张三"));
student1.appendChild(kidEle);
root.appendChild(student1);
/*当一个oDomElement添加到另一个QDomElement时,实际上是在创建原始元素的副本,并将该副本作为子节点
*添加到目标元素中。这意味着添加操作操作会复制原始元素其相关数据,而不是移动原始元素。
*基于上述原因代码QDomElementstudent2=dod.createElement("student");
*可修改为student1=doc.createElement("student");
*以student1之名继续以下的操作。QDomAttr亦是如此。
*本例为使得逻辑更清晰,顾不做修改,综合实例会使用修改后的写法。
**/
//4.2、添加第二个student结点
QDomElement student2=doc.createElement("student");
//为Student结点添加sex、age属性
QDomAttr attr2=doc.createAttribute("sex");
attr2.setNodeValue("女");
student2.setAttributeNode(attr2);
attr2=doc.createAttribute("age");
attr2.setNodeValue("18");
student2.setAttributeNode(attr2);
//为Student结点添加子节点id name
kidEle =doc.createElement("id");
kidEle.appendChild(doc.createTextNode("02"));
student2.appendChild(kidEle);
kidEle=doc.createElement("name");
kidEle.appendChild(doc.createTextNode("李四"));
student2.appendChild(kidEle);
root.appendChild(student2);
//3、保存
QTextStream stream(&file);
//将DOM文档保存到文档流中,并设置缩进字符为4
doc.save(stream,4);
//4、关闭文件
file.close();
doc.clear();
return 0;
}
读Xml文档:
#include <iostream>
#include <QDomComment>
#include <QFile>
#include <QTextStream>
#include<QDebug>
using namespace std;
int main()
{
//1、创建QFile对象,指定要打开的XML文件
QFile file("/home/dwq/Desktop/xxx.xml");
if(!file.open(QIODevice::ReadOnly))
{
qDebug()<<"File open faild!";
return-1;
}
//2、创建QDomDocument对象,用于解析XML
QDomDocument doc;
//通过QFile对象设置QDomDocument的内容
if(!doc.setContent(&file))
{
file.close();
return -1;
}
//关闭文件
file.close();
//3、解析XML
//获取XML根结点
QDomElement root= doc.documentElement();//class结点
//遍历每个student结点
QDomNodeList studentList=root.elementsByTagName("student");//通过标签名获取结点列表
int listSize =studentList.size();
for(int i = 0; i < listSize; ++i)
{
QDomElement student = studentList.at(i).toElement(); //通过索引获取QDomElement对象
QString sex=student.attribute("sex"); //获取sex属性值
QString age =student.attribute("age"); //获取age属性值
/*
*函数原型为
*QDomElement firstChildElement(const QString &tagName = QString()) const;
*解析:参数tagName是可选的,表示要查询的子元素结点的标签名。如果指定了tagName,则返回
*第一个匹配标签的子元素结点;如果没有指定tagName,则返回第一个子元素结点。
**/
QString studentID=student.firstChildElement("id").text(); //获取id元素节点的文本内容
QString studentName=student.firstChildElement("name").text(); //获取name元素节点的文本内容
qDebug()<<"student:";
qDebug()<<"sex:"<<sex;
qDebug()<<"age:"<<age;
qDebug()<<"studentID:"<<studentID;
qDebug()<<"studentName:"<<studentName;
}
return 0;
}
三、使用QDomDocument类读写Xml文档另外一种写法
有些时候我们会遇到一些具有重复结构或嵌套结构等复杂一点的Xml结构,当文件不是很庞大时同样也可以使用QDomDocument类读写Xml文件。这时我们需要一种较为条理的代码结构来完成这个任务。
Operation.h:
#ifndef OPERATION_H
#define OPERATION_H
#include <QString>
#include <QDomDocument>
#include <QList>
struct studentStruct
{
studentStruct(){}
/**
* @brief read
* @param element
*/
void read(QDomElement &element);
/**
* @brief write
* @param doc
* @param element
*/
void write(QDomDocument &doc,QDomElement& element);
QString m_sex;
QString m_age;
QString m_id;
QString m_name;
};
struct classStruct
{
classStruct(){}
/**
* @brief read
* @param element
*/
void read(QDomElement& element);
/**
* @brief write
* @param doc
* @param element
*/
void write(QDomDocument& doc,QDomElement& element);
QList<studentStruct> m_StuList;
};
class Operation
{
public:
Operation();
/**
* @brief Init
*/
void Init();
/**
* @brief Write
* @param fileName
*/
void Write(QString fileName);
/**
* @brief Read
* @param fileName
* @param classData
*/
void Read(QString fileName,classStruct &classData);
private:
classStruct m_class;
};
#endif // OPERATION_H
Operation.cpp:
#include "Operation.h"
#include <QTextStream>
#include <QDebug>
Operation::Operation()
{
}
void Operation::Init()
{
studentStruct stu1,stu2;
stu1.m_sex = "男";
stu1.m_age = "18";
stu1.m_id = "01";
stu1.m_name = "张三";
stu2.m_sex = "女";
stu2.m_age = "18";
stu2.m_id = "02";
stu2.m_name = "李四";
this->m_class.m_StuList.push_back(stu1);
this->m_class.m_StuList.push_back(stu2);
}
void Operation::Write(QString fileName)
{
//1、新建文件
QFile file(fileName);
file.open(QIODevice::WriteOnly);
//2、新建DoM树
QDomDocument doc;
//3、添加说明信息
QString insData=QString("version=\"1.0\" encoding=\"gb23121\"");
QDomProcessingInstruction ins=doc.createProcessingInstruction("xml",insData); //将文档声明添加到DOM树
doc.appendChild(ins);
//4、添加节点信息
//添加根结点class
QDomElement root=doc.createElement("class");
doc.appendChild(root);
this->m_class.write(doc,root);
//5、保存
QTextStream stream(&file);
//将DOM文档保存到文档流中,并设置缩进字符为4
doc.save(stream,4);
//6、关闭文件
file.close();
doc.clear();
}
void Operation::Read(QString fileName, classStruct &classData)
{
//1、创建QFile对象,指定要打开的XML文件
QFile file2(fileName);
if(!file2.open(QIODevice::ReadOnly))
{
qDebug()<<"file2 open faild!";
return;
}
//2、创建QDomDocument对象,用于解析XML
QDomDocument doc2;
//通过QFile对象设置QDomDocument的内容
if(!doc2.setContent(&file2))
{
file2.close();
return;
}
//关闭文件
file2.close();
//3、解析XML
//获取XML根结点
QDomElement root2= doc2.documentElement();//class结点
//将xml数据保存在结构中
classData.read(root2);
}
void studentStruct::read(QDomElement &element)
{
if(!element.isNull())
{
m_sex = element.attribute("sex"); //获取sex属性值
m_age = element.attribute("age"); //获取age属性值
m_id = element.firstChildElement("id").text(); //获取id元素节点的文本内容
m_name = element.firstChildElement("name").text(); //获取name元素节点的文本内容
}
}
void studentStruct::write(QDomDocument &doc, QDomElement &element)
{
element.setAttribute("sex",m_sex);
element.setAttribute("age",m_age);
QDomElement kid=doc.createElement("id");
kid.appendChild(doc.createTextNode(m_id));
element.appendChild(kid);
kid = doc.createElement("name");
kid.appendChild(doc.createTextNode(m_name));
element.appendChild(kid);
}
void classStruct::read(QDomElement &element)
{
if(!element.isNull())
{
#if 0
QDomNodeList studentList = element.elementsByTagName("student");
int listSize = studentList.size();
for(int i = 0; i < listSize; ++i)
{
QDomElement student = studentList.at(1).toElement();
studentStruct item;
item.read(student);
this->m_StuList.push_back(item);
}
#endif
QDomNode firstNode = element.firstChild();
while(!firstNode.isNull())
{
studentStruct item;
QDomElement ele = firstNode.toElement();
if(ele.nodeName() == "student")
{
item.read(ele);
this->m_StuList.push_back(item);
}
firstNode = firstNode.nextSibling();
}
}
}
void classStruct::write(QDomDocument &doc, QDomElement &element)
{
for(auto stu:m_StuList)
{
QDomElement kidEle = doc.createElement("student");
stu.write(doc,kidEle);
element.appendChild(kidEle);
}
}
main.cpp:
#include <iostream>
#include <QDomComment>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include "Operation.h"
using namespace std;
int main()
{
QString fileName = QString("/home/dwq/Desktop/xxx.xml");
Operation op;
//初始化数据
op.Init();
//书写文件
op.Write(fileName);
//读取文件
classStruct xmlData;
op.Read(fileName,xmlData);
for(auto it : xmlData.m_StuList)
{
qDebug()<<"student:";
qDebug()<<"sex:"<<it.m_sex;
qDebug()<<"age:"<<it.m_age;
qDebug()<<"studentID:"<<it.m_id;
qDebug()<<"studentName:"<<it.m_name;
}
return 0;
}
执行结果:
四、总结
选择使用哪种方式主要取决于项目需求和性能要求。如果需要简单地读取和修改XML文档,可以使用QDomDocument类;如果需要处理大型XML文件或需要较低的内存消耗,可以选择QXmlStreamReader和QXmlStreamWriter类或QXmlSimpleReader和QXmlDefaultHandler类。