XML是一种标记语言,被设计用来结构化存储以及传输信息,是一种常用的文档数据结构。
就我个人而言,Qt下读写XML格式文件可以有三种方法:
一是使用纯C++的rapidxml开源库。优点是速度快,媲美strlen()的速度;缺点是处理中文比较麻烦,编码只有ANSI格式。
二是使用QXmlStreamReader类,适当结合QXmlQuery类。优点是灵活性强,节约内存;缺点是理解起来相对较难,还需要一点数据库语言的知识。
三是使用QDomDocument类。是Qt下读写xml文件传统而普遍的做法,缺点就是如果读写的文件很大,会消耗大量的内存空间。
QDomDocument类可以理解为一个QFile,这个类的对象代表了整个文件,通常也是一个xml文件的主节点。还需使用到的类有QDomNode(节点基类)、QDomElement(节点类)、QDomText(内容)、QDomAttr(属性)、QDomProcessingInstruction(文件头)。
<?xml version='1.0' encoding='utf-8'?>
<日销售清单>
<日期 date="2020-05-29">
<时间 time="21:27:41">
<厂家>二汽神龙</厂家>
<品牌>毕加索</品牌>
<报价>39</报价>
<数量>1</数量>
<金额>50</金额>
</时间>
<时间 time="21:27:51">
<厂家>二汽神龙</厂家>
<品牌>毕加索</品牌>
<报价>39</报价>
<数量>1</数量>
<金额>50</金额>
</时间>
<时间 time="21:27:57">
<厂家>二汽神龙</厂家>
<品牌>毕加索</品牌>
<报价>39</报价>
<数量>1</数量>
<金额>50</金额>
</时间>
</日期>
</日销售清单>
头文件
#ifndef DOCXML_H
#define DOCXML_H
#include <QString>
#include <QStringList>
#include <QDomDocument>
#include <QDomElement>
class DocXml
{
public:
DocXml();
static void CreateXml(const QString &filePath); //创建xml 空文件
static void AppendXml(const QString &filePath,QStringList list);
static void WriteXml(QDomDocument &doc,QDomElement &root,QStringList &list);
static void ReadXml(const QString &filePath,QStringList &fList,
QStringList &bList, QStringList &pList,
QStringList &nList, QStringList &tList);
};
#endif // DOCXML_H
创建空的XML文件
#include "docxml.h"
#include <QFile>
#include <QDomDocument> //文件
#include <QDomProcessingInstruction> //格式头部
#include <QDomElement> //元素
#include <QTextStream>
#include <QDebug>
#include <QDateTime>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
DocXml::DocXml()
{
}
void DocXml::CreateXml(const QString &filePath)
{
QFile file(filePath);
if(true == file.exists()) //如果文件存在就不创建
{
cout << "文件已存在";
return;
}
else {
if(file.open(QIODevice::WriteOnly))
{
//创建Xml文档
QDomDocument doc;
//创建XML头部格式
QDomProcessingInstruction ins = doc.createProcessingInstruction("xml","version = \'1.0\' encoding = \'utf-8\'");
//追加元素
doc.appendChild(ins);
//根节点元素
QDomElement root = doc.createElement("日销售清单");
doc.appendChild(root);
//保存
QTextStream stream(&file); //文本流关联文件
doc.save(stream,4); //4 代表缩进4个字符
file.close(); //关闭文件
}
else
{
cout << "打开文件失败";
}
}
}
追加 XML 文件
void DocXml::AppendXml(const QString &filePath, QStringList list)
{
QFile file(filePath);
if(file.open(QIODevice::ReadOnly))
{
//file和xml文档对象关联
QDomDocument doc;
if(doc.setContent(&file)) //关联成功
{
file.close(); //关闭文件
//获取根节点元素
QDomElement root = doc.documentElement();
//获取当前时间
QDateTime date = QDateTime::currentDateTime();
QString strDate = date.toString("yyyy-MM-dd");
//判断根节点下面有没有子节点
if(root.hasChildNodes())
{
//查找最后一个子节点
QDomElement lastEmt = root.lastChildElement();
if(lastEmt.attribute("date") == strDate)
{
//写有效数据
WriteXml(doc,lastEmt,list);
}
else
{
//创建子节点元素
QDomElement dateEmt = doc.createElement("日期");
//dateEmt.setAttribute("date",strDate); //建议写法
//创建date属性
QDomAttr dateAttr = doc.createAttribute("date");
//设置属性的值
dateAttr.setNodeValue(strDate);
//节点和属性关联
dateEmt.setAttributeNode(dateAttr);
//把日期节点追加到根节点
root.appendChild(dateEmt);
//写有效数据
WriteXml(doc,dateEmt,list);
}
}
else
{
//创建子节点元素
QDomElement dateEmt = doc.createElement("日期");
------------------------------------------------
dateEmt.setAttribute("date",strDate); //建议写法
------------------------------------------------
//创建date属性
//QDomAttr dateAttr = doc.createAttribute("date");
//设置属性的值
//dateAttr.setNodeValue(strDate);
//节点和属性关联
//dateEmt.setAttributeNode(dateAttr);
//把日期节点追加到根节点
root.appendChild(dateEmt);
//写有效数据
WriteXml(doc,dateEmt,list);
}
//保存文件
if(file.open(QIODevice::WriteOnly))
{
QTextStream stream(&file);
doc.save(stream,4);
file.close();
}
}
else
{
cout << "关联失败";
}
}
else {
cout << "打开文件失败";
}
}
向XML文件中写入
void DocXml::WriteXml(QDomDocument &doc, QDomElement &root, QStringList &list)
{
//当前时间获取
QDateTime time = QDateTime::currentDateTime();
QString strTime = time.toString("hh:mm:ss");
//创建节点元素
QDomElement timeEmt = doc.createElement("时间");
timeEmt.setAttribute("time",strTime); //设置属性值
//把时间节点追加到日期节点后面
root.appendChild(timeEmt);
QDomElement factory = doc.createElement("厂家");
QDomElement brand = doc.createElement("品牌");
QDomElement price = doc.createElement("报价");
QDomElement num = doc.createElement("数量");
QDomElement total = doc.createElement("金额");
QDomText text = doc.createTextNode(list.at(0));
factory.appendChild(text);
text = doc.createTextNode(list.at(1));
brand.appendChild(text);
text = doc.createTextNode(list.at(2));
price.appendChild(text);
text = doc.createTextNode(list.at(3));
num.appendChild(text);
text = doc.createTextNode(list.at(4));
total.appendChild(text);
timeEmt.appendChild(factory);
timeEmt.appendChild(brand);
timeEmt.appendChild(price);
timeEmt.appendChild(num);
timeEmt.appendChild(total);
}
从XML文件中读取
void DocXml::ReadXml(const QString &filePath,QStringList &fList,
QStringList &bList, QStringList &pList,
QStringList &nList, QStringList &tList)
{
QFile file(filePath);
if(file.open(QIODevice::ReadOnly))
{
//file和xml文档对象关联
QDomDocument doc;
if(doc.setContent(&file))
{
file.close();
QDateTime date = QDateTime::currentDateTime();
QString strDate = date.toString("yyyy-MM-dd");
//获取根节点
QDomElement root = doc.documentElement();
if(root.hasChildNodes())
{
---------------------------------------------------------------------
//推荐用法
QDomElement element = root.firstChildElement("日期"); //日期节点
//判断节点是否为空,获取属性值
if(!element.isNull())
{
QString qstr = element.attribute("date");
}
---------------------------------------------------------------------
//找最后一个元素
QDomElement lastEmt = root.lastChildElement();
if(lastEmt.attribute("date") == strDate) //判断有没有当天日期
{
//找出当前日期下所有时间子节点
QDomNodeList list = lastEmt.childNodes();
for(int i = 0;i < list.size(); ++i)
{
//list.at(0).toElement();
//转换为元素,找到时间节点下所有的子节点
QDomNodeList nodeList = list.at(i).toElement().childNodes();
//厂家
QString factory = nodeList.at(0).toElement().text();
fList.append(factory);
//
QString brand = nodeList.at(0).toElement().text();
bList.append(brand);
QString price = nodeList.at(0).toElement().text();
pList.append(price);
QString num = nodeList.at(0).toElement().text();
nList.append(num);
QString total = nodeList.at(0).toElement().text();
tList.append(total);
}
}
else
{
cout << "没有当天日期";
return ;
}
}
else
{
cout << "没有子节点";
return ;
}
}
else
cout << "file 和 xml 文档对象关联失败";
}
else {
cout << "读取时打开文件失败";
}
}