XML文件可以用来存储项目中的数据,它相当于一个简单的数据库。
XML文件在实际开发中可以经常使用的,因为它非常方便的存储数据,方便存储、方便读取、方便查看、方便管理等。
下面将使用QT语言编写代码操作XML文件 - 增删改查。
一、准备工作
首先看一下XML文件的组成部分
描述信息:这个是xml文件必须要有的一段描述语句;
根节点:xml文件由只有一个根节点(仅有),它是所有子节点的父节点;
子节点:可有多个,必须在根节点内;
属性:存储数据的一种方式。
Qt中提供了QtXml模块来进行xml文件的处理,其中它有3中方式进行操作xml文件;这里主要讲解DOM方式。
操作xml文件需要添加头文件:
#include < QtXml >
#include < QDomDocument >
并且在创建项目时:
-
Visual Studio 编译环境需要勾选xml模块,如下图
-
QT编译环境需要向.pro文件里面添加QT+=xml
二、创建
创建XML文件,并写入内容
- 创建一个xml文件
// 打开或者创建一个XML文件
QFile file("QT_XML.xml");
// 文件存在则创建,否则创建一个文件
if (!file.open(QFileDevice::ReadWrite | QFileDevice::Truncate)) {
QMessageBox::information(NULL, "提示", "文件打开或创建失败!");
return;
}
- 创建一个XML类
QDomDocument doc;
- 创建XML头部格式
// 创建XML处理类,通常用于处理第一行描述信息
QDomProcessingInstruction instruction;
// 创建XML头部格式
instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
// 添加到XML文件中
doc.appendChild(instruction);
如下图,就是创建这么一行
- 创建根节点
使用createElement方法进行创建,创建完成后使用appendChild方法添加到xml文档中
// 创建根节点
QDomElement root = doc.createElement("Library");
doc.appendChild(root);
如下图
- 添加子节点
这里只是单纯的添加一个子节点,并没有其他元素
QDomElement book = doc.createElement("Book");
root.appendChild(book);
如下图
- 添加带属性的子节点
使用setAttribute可以简单的给节点添加属性值;使用createElement是创建一个节点元素;
QDomElement book1 = doc.createElement("Book1");
// 给节点创建属性
book1.setAttribute("ID", 1);
book1.setAttribute("Name", "水浒传"); // 参数一是字符串,参数二可以是任何类型
book1.setAttribute("Price", 64.5);
// 创建子元素
QDomElement description = doc.createElement("Description");
// 设置尖括号中的值
QDomText text = doc.createTextNode("108个拆迁户");
// 添加关系
description.appendChild(text);
book1.appendChild(description);
// 添加子元素2
QDomElement Page = doc.createElement("Page");
QDomText text2 = doc.createTextNode("100页");
Page.appendChild(text2);
book1.appendChild(Page);
// 添加到根节点中
root.appendChild(book1);
流程:
首先创建一个节点,为该节点设置属性值,然后在创建两个子节点,并设置尖括号间的值,最后他们两被添加到第一个子节点中,然后第一个子节点被添加到根节点中,形成一种树结构。如下图
- 将doc写入xml文件
需要使用到文件流QTextStream
QTextStream stream(&file);
doc.save(stream, 4); // 缩进四格
file.close();
- 创建xml文件并插入元素节点,总代码如下
// 创建XML文件,并写入内容
void createXML() {
// 打开或者创建一个XML文件
QFile file("QT_XML.xml");
// 文件存在则创建,否则创建一个文件
if (!file.open(QFileDevice::ReadWrite | QFileDevice::Truncate)) {
QMessageBox::information(NULL, "提示", "文件打开或创建失败!");
return;
}
// 创建一个XML类
QDomDocument doc;
// 创建XML处理类,通常用于处理第一行描述信息
QDomProcessingInstruction instruction;
// 创建XML头部格式
instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
// 添加到XML文件中
doc.appendChild(instruction);
// 创建根节点
QDomElement root = doc.createElement("Library");
doc.appendChild(root);
/******************************************************************************************************************/
// 添加子节点
QDomElement book = doc.createElement("Book");
root.appendChild(book);
/*******************************************************************************************************************/
// 添加带属性的子节点
QDomElement book1 = doc.createElement("Book1");
// 给节点创建属性
book1.setAttribute("ID", 1);
book1.setAttribute("Name", "水浒传"); // 参数一是字符串,参数二可以是任何类型
book1.setAttribute("Price", 64.5);
// 创建子元素
QDomElement description = doc.createElement("Description");
// 设置尖括号中的值
QDomText text = doc.createTextNode("108个拆迁户");
// 添加关系
description.appendChild(text);
book1.appendChild(description);
// 添加子元素2
QDomElement Page = doc.createElement("Page");
QDomText text2 = doc.createTextNode("100页");
Page.appendChild(text2);
book1.appendChild(Page);
// 添加到根节点中
root.appendChild(book1);
/*******************************************************************************************************************/
// 添加子节点3
QDomElement book3 = doc.createElement("Book1");
book3.setAttribute("ID", 2);
book3.setAttribute("Name", "三国演义");
book3.setAttribute("Price", 66.5);
QDomElement description2 = doc.createElement("Description");
QDomText text3 = doc.createTextNode("魏蜀吴打架");
description2.appendChild(text3);
book3.appendChild(description2);
QDomElement page = doc.createElement("Page");
QDomText text4 = doc.createTextNode("300页");
page.appendChild(text4);
book3.appendChild(page);
root.appendChild(book3);
/*******************************************************************************************************************/
// 将其写入到xml文件中
QTextStream stream(&file);
doc.save(stream, 4); // 缩进四格
file.close();
}
当执行完成后,会在项目路径创建一个xml文件,内容如下图:
三、添加
往xml文件中添加节点元素
例:
/* 创建一个一级子节点,子节点包含属性,包含二级子节点 */
1.打开文件,并定义xml文档类,并关联file文件
简单来说,对已经存在的xml文件,我们操作它前,需要先使用xml对象与文件对象进行关联
// 打开文件
QFile file("QT_XML.xml");
if (!file.open(QFileDevice::ReadOnly)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
QDomDocument doc;
// 将doc与file关联起来
// 这个函数从IO设备dev中读取XML文档,如果内容被成功解析,则返回true;否则返回false。
if (!doc.setContent(&file)) {
QMessageBox::information(NULL, "提示", "操作的文件不是XML文件!");
file.close();
return;
}
// 关联后可以关闭文件了
file.close();
2. 获取根节点
获取根节点对象
QDomElement root = doc.documentElement();
3. 创建一级子节点,并设置属性
使用createElement可以创建子节点元素;使用setAttribute可以设置属性
QDomElement book = doc.createElement("Book1");
book.setAttribute("ID", 3); // 参数1是字符串,参数2可以是任何类型
book.setAttribute("Name", "西游记");
book.setAttribute("Price", "68.5");
假设创建好后,在xml文件中是这样显示的:
4. 为一级子节点创建子节点
QDomElement description = doc.createElement("Description"); // 创建节点
QDomText text = doc.createTextNode("两个人,一匹马,两个动物"); // 创建节点尖括号间的值
description.appendChild(text); // 尖括号间的值的对象被添加到2级子节点中
book.appendChild(description); // 2级子节点被添加到1级子节点中
QDomElement page = doc.createElement("Page");
text = doc.createTextNode("81页");
page.appendChild(text);
book.appendChild(page);
假设创建好后,在xml文件中是这样显示的:
5.将一级子节点添加到根节点中
记得,当子节点们操作完成后,需要添加到根节点中,否则是无法添加成功的
// 添加到根节点
root.appendChild(book);
6. 使用文件流写入xml文件中
if (!file.open(QFileDevice::WriteOnly | QFileDevice::Truncate)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
// 输出到文件
QTextStream stream(&file);
doc.save(stream, 4); // 缩进4格
file.close();
7. 为已存在的xml文件添加节点元素,总代码如下
// 往XML文件中写内容(添加内容)
void addXML() {
/* 创建一个一级子节点,子节点包含属性,包含二级子节点*/
// 打开文件
QFile file("QT_XML.xml");
if (!file.open(QFileDevice::ReadOnly)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
QDomDocument doc;
// 将doc与file关联起来
// 这个函数从IO设备dev中读取XML文档,如果内容被成功解析,则返回true;否则返回false。
if (!doc.setContent(&file)) {
QMessageBox::information(NULL, "提示", "操作的文件不是XML文件!");
file.close();
return;
}
file.close();
// 获取根节点
QDomElement root = doc.documentElement();
// 创建一级节点
QDomElement book = doc.createElement("Book1");
book.setAttribute("ID", 3);
book.setAttribute("Name", "西游记");
book.setAttribute("Price", "68.5");
// 创建二级节点1
QDomElement description = doc.createElement("Description");
QDomText text = doc.createTextNode("两个人,一匹马,两个动物");
description.appendChild(text);
book.appendChild(description);
QDomElement page = doc.createElement("Page");
text = doc.createTextNode("81页");
page.appendChild(text);
book.appendChild(page);
创建二级节点2,3,4
//QDomElement author2 = doc.createElement("Author");
//author2.setAttribute("Name", "吴承恩");
//QDomElement author3 = doc.createElement("Author");
//author3.setAttribute("Sex", "男");
//QDomElement author4 = doc.createElement("Author");
//author4.setAttribute("Age", 82);
//book.appendChild(author2);
//book.appendChild(author3);
//book.appendChild(author4);
// 添加到根节点
root.appendChild(book);
if (!file.open(QFileDevice::WriteOnly | QFileDevice::Truncate)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
// 输出到文件
QTextStream stream(&file);
doc.save(stream, 4); // 缩进4格
file.close();
}
执行完如上代码,会在xml文件中添加指定的节点元素,如下图
四、删除
删除子节点
例:
/* 删除book 和 book1其中一个子节点 */
1. 与上类似,打开文件,关联文件,获取根节点
…
2. 删除Book节点
// 获取节点名字为Book的所有节点
QDomNodeList list = doc.elementsByTagName("Book");
for (int i = 0; i < list.size(); i++) {
// 获取节点
QDomElement element = list.at(i).toElement();
// 删除子节点
root.removeChild(element);
}
流程:
首先通过elementsByTagName获取名字为“Book”的所有节点;遍历,获取其中每一个元素,转换为QDomElement 类型,进行删除
假设执行完,xml中将会是这样:
3. 删除指定的节点
上面是将节点名字为Book的节点都删除;那么,如果我只是向删除其中一个呢?
这里可以进行判断一下,在进行删除,使用属性的唯一值进行判断即可
list = doc.elementsByTagName("Book1");
int size = list.count();
for (int i = 0; i < list.count(); i++) {
// 获取节点
QDomElement element = list.at(i).toElement();
// 进行判断(返回属性的值进行判断)
if (element.attribute("ID") == "3") {
root.removeChild(list.at(i));
}
}
这里使用attribute方法获取对应参数的属性的值,然后与指定字符串进行判断,相等则使用removeChild方法进行删除
4. 最后再使用文件流输出到文件即可
与上面是相同的…
5. 删除节点,代码汇总
// 删除XML文件中的某些内容
void delXML() {
/* 删除book 和 book1的一个子节点*/
// 打开文件
QFile file("QT_XML.xml");
if (!file.open(QFileDevice::ReadOnly)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
QDomDocument doc;
if (!doc.setContent(&file)) {
QMessageBox::information(NULL, "提示", "操作的文件不是XML文件!");
file.close();
return;
}
file.close();
// 获得根节点
QDomElement root = doc.documentElement();
/* 删除所有的Book节点 */
// 获取节点名字为Book的所有节点
QDomNodeList list = doc.elementsByTagName("Book");
for (int i = 0; i < list.size(); i++) {
// 获取节点
QDomElement element = list.at(i).toElement();
// 删除子节点
root.removeChild(element);
}
// 获取节点名字为Book1的所有节点
list = doc.elementsByTagName("Book1");
int size = list.count();
for (int i = 0; i < list.count(); i++) {
// 获取节点
QDomElement element = list.at(i).toElement();
if (element.attribute("ID") == "3") {
root.removeChild(list.at(i));
}
}
if (!file.open(QFileDevice::WriteOnly | QFileDevice::Truncate)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
// 输出到文件
QTextStream stream(&file);
doc.save(stream, 4); // 缩进4格
file.close();
}
执行后xml文件如下图:
当然你也可以删除子节点的子节点,方法类似,定位到对应节点然后使用父节点removeChild就可以了。
QDomNode QDomNode::parentNode() const此方法可以返回父节点。
五、修改
修改(更改)XML中节点的值
例:
/* 将Book1中id为2的节点的Price属性更改数值为88.5;修改其子节点Description内容为 “魏蜀吴在玩过家家” */
1. 修改属性值
// 获取所有Book1节点
QDomNodeList list = root.elementsByTagName("Book1");
/* 修改属性的值 */
for (int i = 0; i < list.size(); i++) {
QDomElement element = list.at(i).toElement();
// 找到ID等于2的节点
if (element.attribute("ID") == "2") {
// 修改属性值
element.setAttribute("Price", 88.5);
break;
}
}
当执行完代码后:
2. 修改节点值
这个可能有点复杂
首先当然是先获取到待修改节点对象,然后通过调用firstChild方法,将尖括号间的内容实例化为QDomNode对象,然后待修改节点对象调用firstChild().setNodeValue()设置尖括号中的值,然后再次将尖括号中的内容实例化为对象,最后,调用replaceChild函数将两个尖括号的对象互相替换。
看字面有点抽象,没事,看代码应该就会懂了
for (int i = 0; i < list.size(); i++) {
QDomElement element = list.at(i).toElement();
// 找到ID等于2的节点
if (element.attribute("ID") == "2") {
// 获得子节点
QDomNode node = element.namedItem("Description");
// 尖括号之间的内容作为子节点出现(修改前)
QDomNode oldNode = node.firstChild();
// 修改尖括号之间的值
node.firstChild().setNodeValue("魏蜀吴在玩过家家");
// 尖括号之间的内容作为子节点出现(修改后)
QDomNode newNode = node.firstChild();
// 将新旧内容子节点进行替换
node.replaceChild(newNode, oldNode);
break;
}
}
解释:
首先获取需要修改尖括号间的值的对象
// 获得子节点
QDomNode node = element.namedItem(“Description”);
也就是下图方框中的对象
然后将尖括号间的内容实例化为对象
// 尖括号之间的内容作为子节点出现(修改前)
QDomNode oldNode = node.firstChild();
也即是下图方框中的对象
然后修改尖括号间的值
node.firstChild().setNodeValue(“魏蜀吴在玩过家家”);
当然,修改后,并不是值立马就改变了,还需要做其他操作。
然后再次将尖括号间的内容实例化为对象
// 尖括号之间的内容作为子节点出现(修改后)
QDomNode newNode = node.firstChild();
最后将修改前的节点和修改后的节点进行替换
// 将新旧内容子节点进行替换
node.replaceChild(newNode, oldNode);
得出如下效果:
最后使用文件流写入xml文件即可。
3. 修改xml中的节点值,代码汇总
// 更新XML中的内容
void altXML() {
/* 将Book1中id为2的节点的Price属性更改数值为88.5;修改其子节点Description内容为“魏蜀吴在玩过家家”*/
// 打开文件
QFile file("QT_XML.xml");
if (!file.open(QFileDevice::ReadOnly)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
QDomDocument doc;
if (!doc.setContent(&file)) {
QMessageBox::information(NULL, "提示", "操作的文件不是XML文件!");
file.close();
return;
}
file.close();
// 获得根节点
QDomElement root = doc.documentElement();
// 获取所有Book1节点
QDomNodeList list = root.elementsByTagName("Book1");
/* 修改属性的值 */
for (int i = 0; i < list.size(); i++) {
QDomElement element = list.at(i).toElement();
// 找到ID等于2的节点
if (element.attribute("ID") == "2") {
// 修改属性值
element.setAttribute("Price", 88.5);
break;
}
}
/* 修改尖括号之间的值 */
for (int i = 0; i < list.size(); i++) {
QDomElement element = list.at(i).toElement();
// 找到ID等于2的节点
if (element.attribute("ID") == "2") {
// 获得子节点
QDomNode node = element.namedItem("Description");
// 尖括号之间的内容作为子节点出现(修改前)
QDomNode oldNode = node.firstChild();
// 修改尖括号之间的值
node.firstChild().setNodeValue("魏蜀吴在玩过家家");
// 尖括号之间的内容作为子节点出现(修改后)
QDomNode newNode = node.firstChild();
// 将新旧内容子节点进行替换
node.replaceChild(newNode, oldNode);
break;
}
}
if (!file.open(QFileDevice::WriteOnly | QFileDevice::Truncate)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
// 输出到文件
QTextStream stream(&file);
doc.save(stream, 4); // 缩进4格
file.close();
}
执行完如下效果:
六、读取
读取指定节点中值
例:
/* 读取Book1节点,ID为1的节点的所有数据 */
// 获取所有Book1节点
QDomNodeList list = root.elementsByTagName(“Book1”);
1. 首先打开文件,关联对象
记得别关闭文件哦!
// 打开文件
QFile file("QT_XML.xml");
if (!file.open(QFileDevice::ReadOnly)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
QDomDocument doc;
if (!doc.setContent(&file)) {
QMessageBox::information(NULL, "提示", "操作的文件不是XML文件!");
file.close();
return;
}
2. 获取属性中的值
/* 获取属性中的值 */
for (int i = 0; i < list.count(); i++) {
// 获取链表中的值
QDomElement element = list.at(i).toElement();
// 找到需要读取的节点
if (element.attribute("Name") == "水浒传") {
// 通过attribute方法返回属性中的值
qDebug() << "子节点:" << element.nodeName();
qDebug() << "ID属性:" << element.attribute("ID");
qDebug() << "Name属性:" << element.attribute("Name");
qDebug() << "Price属性:" << element.attribute("Price");
}
}
思路:
定位到当前节点后,使用attribute函数可以返回当前属性中的值
使用nodeName方法可以获取节点名字
如下效果:
3. 获取尖括号间的值
for (int i = 0; i < list.count(); i++) {
// 获取链表中的值
QDomElement element = list.at(i).toElement();
// 找到需要读取的节点
if (element.attribute("Name") == "水浒传") {
// 获得子节点
QDomNode description = element.namedItem("Description");
QDomNode page = element.namedItem("Page");
qDebug() << "Description:" << description.firstChild().nodeValue();
qDebug() << "Page:" << page.firstChild().nodeValue();
// 也可以使用childNodes方法获取所有的子节点
/*QDomNodeList nodeList = element.childNodes();
qDebug() << nodeList.at(0).firstChild().nodeValue();
qDebug() << nodeList.at(1).firstChild().nodeValue();*/
}
}
思路:
获得尖括号节点对象后,使用.firstChild().nodeValue();就可以获得尖括号间的值了
使用childNodes方法可以获取所有子节点,返回值是QDomNodeList 。
运行如下图:
4. 最后记得关闭文件哦
file.close();
5. 读取xml节点值,代码汇总
// 读取xml中的内容
void readXML() {
/* 读取Book1节点,ID为1的节点的所有数据 */
// 打开文件
QFile file("QT_XML.xml");
if (!file.open(QFileDevice::ReadOnly)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
QDomDocument doc;
if (!doc.setContent(&file)) {
QMessageBox::information(NULL, "提示", "操作的文件不是XML文件!");
file.close();
return;
}
// 获得根节点
QDomElement root = doc.documentElement();
qDebug() << "根节点:" << root.nodeName();
// 获取所有Book1节点
QDomNodeList list = root.elementsByTagName("Book1");
/* 获取属性中的值 */
for (int i = 0; i < list.count(); i++) {
// 获取链表中的值
QDomElement element = list.at(i).toElement();
// 找到需要读取的节点
if (element.attribute("Name") == "水浒传") {
// 通过attribute方法返回属性中的值
qDebug() << "子节点:" << element.nodeName();
qDebug() << "ID属性:" << element.attribute("ID");
qDebug() << "Name属性:" << element.attribute("Name");
qDebug() << "Price属性:" << element.attribute("Price");
}
}
/* 获取尖括号间的值 */
for (int i = 0; i < list.count(); i++) {
// 获取链表中的值
QDomElement element = list.at(i).toElement();
// 找到需要读取的节点
if (element.attribute("Name") == "水浒传") {
// 获得子节点
QDomNode description = element.namedItem("Description");
QDomNode page = element.namedItem("Page");
qDebug() << "Description:" << description.firstChild().nodeValue();
qDebug() << "Page:" << page.firstChild().nodeValue();
// 也可以使用childNodes方法获取所有的子节点
/*QDomNodeList nodeList = element.childNodes();
qDebug() << nodeList.at(0).firstChild().nodeValue();
qDebug() << nodeList.at(1).firstChild().nodeValue();*/
}
}
file.close();
}
七、总结
到了这里,那么恭喜你已经完全学会QT如何操作XML文件了,可以去写项目去了。
这篇文章让我从0 学会了Qt读写XML文件,非常感谢原作者!
原文链接:https://blog.csdn.net/cpp_learner/article/details/117876073