简介XML
XML(Extensible Markup Language,可扩展标记语言),是一种类似于HTML的标记语言,设计目的是用来传输数据,而不是显示数据。XML的标签没有被预定义,用户需要在使用时自行进行定义。XML是W3C(万维网联盟)的推荐标准。相对于数据库表格的二维表示,XML使用的树形结构更能表现出数据的包含关系,作为一种文本文件格式,XML简单明了的特性使得它在信息存储和描述领域非常流行。
Qt中提供了Qt XML模块来进行XML文档的处理,这里主要提供了两种解析方法: DOM方法,可以进行读写;SAX方法,可以进行读取。但是,从Qt 5开始Qt XML模块不再提供维护,而是推荐使用Qt Core模块中的QXmlStreamReader和QXmlStreamWriter进行XML读取和写入,这是一种基于流的方法。
如果要使用Qt XML模块,需要在项目文件(.pro文件)中添加QT += xml一行代码。
标准的XML文档示例:
<?xml version="1.0" encoding="UTF-8"?>
<library>
<book id="01">
<title>Qt</title>
<author>shiming</author>
</book>
<book id="02">
<title>Linux</title>
<author>yafei</author>
</book>
</library>
DOM
DOM(Document Object Model,文档对象模型),是W3C的推荐标准。它提供了一个接口来访问和改变一个XML文件的内容和结构,可以将XML文档表示为一个存储在内存中具有层次的树视图。文档本身由QDomDocument对象来表示,而文档树中所有的DOM节点都是QDomNode类的子类。
在Qt中使用QDomProcessingInstruction类来表示XML说明。元素对应QDomElement类。属性对应QDomAttr类。文本内容由QDomText类表示。所有的DOM节点,比如这里的说明、元素、属性和文本等,都使用QDomNode来表示。
下面用一个简单的实例来介绍XML文件的创建与读取。
XML创建
//生成配置文件
void Login::createConfigXML()
{
//配置文件 参数
QDomDocument doc;
//根元素
QDomElement root;
//界面元素
QDomElement interface;
//界面子元素
QDomElement child;
//控件文本
QDomText text;
// 添加处理指令即XML说明
QDomProcessingInstruction instruction;
instruction = doc.createProcessingInstruction("xml",
"version=\"1.0\" encoding=\"UTF-8\"");
doc.appendChild(instruction);
// 添加根元素
root = doc.createElement("色选机软件系统");
doc.appendChild(root);
//【一】管理员界面
interface = doc.createElement("管理员界面");
//...【1】
child = doc.createElement("工作模式");
text = doc.createTextNode("异色模式");
child.appendChild(text);
interface.appendChild(child);
root.appendChild(interface);
//【二】背景板界面
interface = doc.createElement("背景板界面");
//...【1】
child = doc.createElement("镜头号");
text = doc.createTextNode("1");
child.appendChild(text);
interface.appendChild(child);
//...【2】
child = doc.createElement("背景");
text = doc.createTextNode("红色");
child.appendChild(text);
interface.appendChild(child);
//添加界面数据
root.appendChild(interface);
//创建配置文件
QFile file("ColorConfig.xml");
if(!file.open(QIODevice::Truncate | QIODevice::WriteOnly))
{
QMessageBox::about(NULL, tr("错误"), tr("生成配置文件失败,请重试!"));
return;
}
QTextStream out(&file);
// 将文档保存到文件,4为子元素缩进字符数
doc.save(out, 4);
file.close();
}
生成的配置文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<色选机软件系统>
<管理员界面>
<工作模式>异色模式</工作模式>
</管理员界面>
<背景板界面>
<镜头号>1</镜头号>
<背景>红色</背景>
</背景板界面>
</色选机软件系统>
XML读取
//读取配置文件
void Login::readConfigXML()
{
QFile file("ColorConfig.xml");
if(!file.exists())
{
QMessageBox::about(NULL, tr("提示"), tr("未发现配置文件"));
return;
}
if (!file.open(QIODevice::ReadOnly))
return;
QDomDocument Qdoc;
if (!Qdoc.setContent(&file))
{
file.close();
return ;
}
file.close();
//【一】管理员界面
QDomNodeList list = Qdoc.elementsByTagName("管理员界面");
QDomNodeList child = list.at(0).childNodes();
for(int i = 0; i < child.count(); ++i)
{
//输出子元素名
qDebug()<< child.at(i).toElement().tagName() << endl;
//输出字元素数据
qDebug()<< child.at(i).toElement().text()) << endl;
}
//【二】背景板界面
list = Qdoc.elementsByTagName("背景板界面");
child = list.at(0).childNodes();
for(int i = 0; i < child.count(); ++i)
{
//输出子元素名
qDebug()<< child.at(i).toElement().tagName() << endl;
//输出字元素数据
qDebug()<< child.at(i).toElement().text()) << endl;
}
}
还有另一种方式读取:
QFile file("ColorConfig.xml");
if (!file.open(QIODevice::ReadOnly)) return ;
QDomDocument doc;
if (!doc.setContent(&file)) { file.close(); return ; }
file.close();
QDomElement docElem = doc.documentElement();
QDomNode n = docElem.firstChild();
while(!n.isNull()) {
if (n.isElement()) {
QDomElement e = n.toElement();
QDomNodeList list = e.childNodes();
for (int i=0; i<list.count(); i++) {
QDomNode node = list.at(i);
if(node.isElement())
{
//输出子元素名
qDebug()<< node.toElement().tagName() << endl;
//输出字元素数据
qDebug()<< node.toElement().text()) << endl;
}
} n = n.nextSibling();
}
“重写XML不能覆盖原内容问题”解决
如果我们想覆盖XML中的原数据,重新写入数据,使用
file.open(QIODevice::Truncate | QIODevice::WriteOnly)
这种方式打开文件即可,Truncate 表示重写,将原文件数据清空。但是我在做项目中碰到如下问题,重新写入数据时,原数据没能覆盖,新数据也添加了进去,如下:
<?xml version="1.0" encoding="UTF-8"?>
<色选机软件系统>
<管理员界面>
<工作模式>异色模式</工作模式>
</管理员界面>
<背景板界面>
<镜头号>1</镜头号>
<背景>红色</背景>
</背景板界面>
</色选机软件系统>
<?xml version="1.0" encoding="UTF-8"?>
<色选机软件系统>
<管理员界面>
<工作模式>黄白模式</工作模式>
</管理员界面>
<背景板界面>
<镜头号>3</镜头号>
<背景>蓝色</背景>
</背景板界面>
</色选机软件系统>
最终发现原因:
我的项目中,软件打开时,默认加载配置文件的数据,然而我把读取、创建XML元素的对象们设置为全局的了,
//配置文件 参数
QDomDocument doc;
//根元素
QDomElement root;
//界面元素
QDomElement interface;
//界面子元素
QDomElement child;
//控件文本
QDomText text;
导致软件打开时,读取配置文件,这些变量都被占用,并没有释放。然后我再去重写XML内容时,就不可以将已占用的数据清空替换,导致新的配置文件数据在原数据下方产生。
解决方法:
将这些读取、创建XML元素的对象们设置为局部变量,一次用完自动释放,不妨碍其他操作。这样就正确了。