学习记录
使用QDomDocument读取xml
QtWidgets 是系统弹窗需要头文件
包含的头文件:
#include <QtXml>
#include <QDomDocument>
#include <QtWidgets>
1.创建:
void XmlStudy::Creat()
{
//相对路径
QFile file(qApp->applicationDirPath() + "/xml/" + "999.xml");
// 文件存在则创建,否则创建一个文件
if (!file.open(QFileDevice::ReadWrite | QFileDevice::Truncate)) {
QMessageBox::information(NULL, QStringLiteral("提示"), QStringLiteral("文件打开或创建失败!"));
return;
}
QDomDocument doc;
QDomProcessingInstruction instruction;
// 创建XML头部格式
instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
// 添加到XML文件中
doc.appendChild(instruction);
//创建根节点
QDomElement Node_Root = doc.createElement(QStringLiteral("中国"));
doc.appendChild(Node_Root);// appendChild() 绑定关系:doc的下一层为root
// 给根节点创建属性 可选择是否添加
Node_Root.setAttribute(QStringLiteral("标签"), QStringLiteral("Number One"));
{//创建一级节点1
QDomElement Node_FirstLevel_1 = doc.createElement(QStringLiteral("河南省"));
Node_Root.appendChild(Node_FirstLevel_1);
// 给一级节点创建属性 可选择是否添加
Node_FirstLevel_1.setAttribute(QStringLiteral("人口"), QStringLiteral("1000万人"));// 参数一是字符串,参数二可以是任何类型
Node_FirstLevel_1.setAttribute(QStringLiteral("GTP"), QStringLiteral("100000亿元"));
Node_FirstLevel_1.setAttribute(QStringLiteral("ID"), 1);
// 给一级节点添加子元素1
QDomElement Element_1 = doc.createElement(QStringLiteral("郑州"));
Node_FirstLevel_1.appendChild(Element_1);
// 设置子元素1的值
QDomText text = doc.createTextNode("1");
Element_1.appendChild(text);
// 添加子元素2
QDomElement Element_2 = doc.createElement(QStringLiteral("周口"));
Node_FirstLevel_1.appendChild(Element_2);
QDomText text2 = doc.createTextNode("2");
Element_2.appendChild(text2);
}
{
//创建一级节点2
QDomElement Node_FirstLevel_2 = doc.createElement(QStringLiteral("河北省"));
Node_Root.appendChild(Node_FirstLevel_2);
// 给一级节点创建属性 可选择是否添加
Node_FirstLevel_2.setAttribute(QStringLiteral("人口"), QStringLiteral("1000万人"));
Node_FirstLevel_2.setAttribute(QStringLiteral("GTP"), QStringLiteral("100000亿元"));
Node_FirstLevel_2.setAttribute(QStringLiteral("ID"), 2);
// 给一级节点添加子元素1
QDomElement Element_1 = doc.createElement(QStringLiteral("石家庄"));
Node_FirstLevel_2.appendChild(Element_1);
// 设置子元素1的值
QDomText text = doc.createTextNode("1");
Element_1.appendChild(text);
// 添加子元素2
QDomElement Element_2 = doc.createElement(QStringLiteral("邯郸"));
Node_FirstLevel_2.appendChild(Element_2);
QDomText text2 = doc.createTextNode("2");
Element_2.appendChild(text2);
}
//保存
QTextStream stream(&file);
doc.save(stream, 4);
file.close();
}
生成的xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<中国 标签="Number One">
<河南省 GTP="100000亿元" ID="1" 人口="1000万人">
<郑州>1</郑州>
<周口>2</周口>
</河南省>
<河北省 GTP="100000亿元" ID="2" 人口="1000万人">
<石家庄>1</石家庄>
<邯郸>2</邯郸>
</河北省>
</中国>
2.增加
void XmlStudy::Add()
{
QFile file(qApp->applicationDirPath() + "/xml/" + "999.xml");
if (!file.open(QFileDevice::ReadOnly)) {
QMessageBox::information(NULL, QStringLiteral("提示"), QStringLiteral("文件打开失败!"));
return;
}
QDomDocument doc;
//读取XML文档
if (!doc.setContent(&file)) {
QMessageBox::information(NULL, QStringLiteral("提示"), QStringLiteral("操作的文件不是XML文件!"));
file.close();
return;
}
file.close();
// 获取根节点
QDomElement Node_Root = doc.documentElement();
// 在原基础上添加一级节点3
QDomElement Node_FirstLevel_3 = doc.createElement(QStringLiteral("四川省"));
Node_Root.appendChild(Node_FirstLevel_3);
Node_FirstLevel_3.setAttribute(QStringLiteral("人口"), QStringLiteral("1000万人"));
Node_FirstLevel_3.setAttribute(QStringLiteral("GTP"), QStringLiteral("100000亿元"));
Node_FirstLevel_3.setAttribute(QStringLiteral("ID"), 3);
// 创建二级节点1
QDomElement Element_1 = doc.createElement(QStringLiteral("成都"));
QDomText text = doc.createTextNode("1");
Element_1.appendChild(text);
Node_FirstLevel_3.appendChild(Element_1);
QDomElement Element_2 = doc.createElement(QStringLiteral("绵阳"));
text = doc.createTextNode("2");
Element_2.appendChild(text);
Node_FirstLevel_3.appendChild(Element_2);
if (!file.open(QFileDevice::WriteOnly | QFileDevice::Truncate)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
// 输出到文件
QTextStream stream(&file);
doc.save(stream, 4); // 缩进4格
file.close();
}
增加四川省节点后的xml如下:
<?xml version='1.0' encoding='UTF-8'?>
<中国 标签="Number One">
<河南省 ID="1" GTP="100000亿元" 人口="1000万人">
<郑州>1</郑州>
<周口>2</周口>
</河南省>
<河北省 ID="2" GTP="100000亿元" 人口="1000万人">
<石家庄>1</石家庄>
<邯郸>2</邯郸>
</河北省>
<四川省 ID="3" GTP="100000亿元" 人口="1000万人">
<成都>1</成都>
<绵阳>2</绵阳>
</四川省>
</中国>
3.删除
void XmlStudy::Delete()
{
QFile file(qApp->applicationDirPath() + "/xml/" + "999.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 Node_Root = doc.documentElement();
{
// 获取一级节点名字为 一级节点3 的所有节点
QDomNodeList list = doc.elementsByTagName(QStringLiteral("四川省"));
int size = list.count();
for (int i = 0; i < list.count(); i++) {
// 获取节点
QDomElement element = list.at(i).toElement();
if (element.attribute(QStringLiteral("ID")) == "3") { //这里判断一下ID的目的是 为了防止有多个名字为 四川省 的一级节点 做区分 删除对应id的四川省
{
//删除节点的子元素
QDomNode node = element.namedItem(QStringLiteral("成都"));
element.removeChild(node);
}
//{
//删除此节点的全部信息
//Node_Root.removeChild(list.at(i));
//}
//{
//删除节点的属性
//element.removeAttribute(QStringLiteral("人口"));
//}
}
}
}
if (!file.open(QFileDevice::WriteOnly | QFileDevice::Truncate)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
// 输出到文件
QTextStream stream(&file);
doc.save(stream, 4);
file.close();
}
删除四川省下的成都值 (删除节点属性 见代码里的注释)
删除前xml:
<?xml version='1.0' encoding='UTF-8'?>
<中国 标签="Number One">
<河南省 ID="1" GTP="100000亿元" 人口="1000万人">
<郑州>1</郑州>
<周口>2</周口>
</河南省>
<河北省 ID="2" GTP="100000亿元" 人口="1000万人">
<石家庄>1</石家庄>
<邯郸>2</邯郸>
</河北省>
<四川省 ID="3" GTP="100000亿元" 人口="1000万人">
<成都>1</成都>
<绵阳>2</绵阳>
</四川省>
</中国>
删除后:
<?xml version='1.0' encoding='UTF-8'?>
<中国 标签="Number One">
<河南省 GTP="100000亿元" 人口="1000万人" ID="1">
<郑州>1</郑州>
<周口>2</周口>
</河南省>
<河北省 GTP="100000亿元" 人口="1000万人" ID="2">
<石家庄>1</石家庄>
<邯郸>2</邯郸>
</河北省>
<四川省 GTP="100000亿元" 人口="1000万人" ID="3">
<绵阳>2</绵阳>
</四川省>
</中国>
4.修改
void XmlStudy::Ament()
{
QFile file(qApp->applicationDirPath() + "/xml/" + "999.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 Node_Root = doc.documentElement();
// 获取所有Book1节点
QDomNodeList list = Node_Root.elementsByTagName(QStringLiteral("四川省"));
{
/* 修改属性的值 */
for (int i = 0; i < list.size(); i++) {
QDomElement element = list.at(i).toElement();
// 找到ID等于2的节点
if (element.attribute("ID") == "3") {
// 修改属性值
element.setAttribute("GTP", 200000);
break;
}
}
}
{
/* 修改尖括号之间的值 */
for (int i = 0; i < list.size(); i++) {
QDomElement element = list.at(i).toElement();
if (element.attribute("ID") == "3") {
// 获得子节点
QDomNode node = element.namedItem(QStringLiteral("成都"));
node.firstChild().setNodeValue("999");
break;
}
}
}
if (!file.open(QFileDevice::WriteOnly | QFileDevice::Truncate)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
// 输出到文件
QTextStream stream(&file);
doc.save(stream, 4);
file.close();
}
将四川省 GTP修改为200000亿元 将成都值修改为999
修改前:
<?xml version='1.0' encoding='UTF-8'?>
<中国 标签="Number One">
<河南省 ID="1" GTP="100000亿元" 人口="1000万人">
<郑州>1</郑州>
<周口>2</周口>
</河南省>
<河北省 ID="2" GTP="100000亿元" 人口="1000万人">
<石家庄>1</石家庄>
<邯郸>2</邯郸>
</河北省>
<四川省 ID="3" GTP="100000亿元" 人口="1000万人">
<成都>1</成都>
<绵阳>2</绵阳>
</四川省>
</中国>
修改后:
<?xml version='1.0' encoding='UTF-8'?>
<中国 标签="Number One">
<河南省 ID="1" GTP="100000亿元" 人口="1000万人">
<郑州>1</郑州>
<周口>2</周口>
</河南省>
<河北省 ID="2" GTP="100000亿元" 人口="1000万人">
<石家庄>1</石家庄>
<邯郸>2</邯郸>
</河北省>
<四川省 ID="3" GTP="200000" 人口="1000万人">
<成都>999</成都>
<绵阳>2</绵阳>
</四川省>
</中国>
5.查找
void XmlStudy::Find()
{
QFile file(qApp->applicationDirPath() + "/xml/" + "999.xml");
if (!file.open(QFileDevice::ReadOnly)) {
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
QDomDocument doc;
if (!doc.setContent(&file)) {
QMessageBox::information(NULL, "提示", "操作的文件不是XML文件!");
file.close();
return;
}
// 获得根节点
QDomElement Node_Root = doc.documentElement();
qDebug() << QStringLiteral("根节点:") << Node_Root.nodeName();
// 获取所有Book1节点
QDomNodeList list = Node_Root.elementsByTagName(QStringLiteral("四川省"));
/* 获取属性中的值 */
for (int i = 0; i < list.count(); i++) {
QDomElement element = list.at(i).toElement();
qDebug() << QStringLiteral("子节点:") << element.nodeName();
qDebug() << QStringLiteral("ID:") << element.attribute("ID");
qDebug() << QStringLiteral("人口") << element.attribute(QStringLiteral("人口"));
qDebug() << QStringLiteral("GTP") << element.attribute(QStringLiteral("GTP"));
}
// 获取节点子元素的值
for (int i = 0; i < list.count(); i++) {
QDomElement element = list.at(i).toElement();
// 找到需要读取的节点
QDomNode note1 = element.namedItem(QStringLiteral("成都"));
QDomNode note2 = element.namedItem(QStringLiteral("绵阳"));
qDebug() << QStringLiteral("成都 的值为:") << note1.firstChild().nodeValue();
qDebug() << QStringLiteral("绵阳 的值为:") << note2.firstChild().nodeValue();
// 使用childNodes方法获取所有子节点
//QDomNodeList nodeList = element.childNodes();
//qDebug() << nodeList.at(0).firstChild().nodeValue();
//qDebug() << nodeList.at(1).firstChild().nodeValue();
}
file.close();
}
qDebug()输出为:
"根节点:" "中国"
"子节点:" "四川省"
"ID:" "3"
"人口" "1000万人"
"GTP" "200000"
"成都 的值为:" "999"
"绵阳 的值为:" "2"
6.生成的XML 节点中属性会随机乱序问题
xml的Attribute属性是无关排序的,怎么排都一样,对于解析没有影响。
不过可以通过锁定哈希,设定固定的随机数种子来确保在特定机器上保存的属性顺序一致。
但是,由于不同机器的随机数种子不同,这种方法在不同设备间无法保证属性顺序的一致性
方法:
extern Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed;//这句放在头文件后面
qt_qhash_seed.store(0);//这句放在对于xml文件操作之前
亲测有效
另外,QXmlStreamWriter可以按照开发者的意愿任意排序元素属性的顺序。若生成的xml文件主要给人阅读,那么推荐使用QXmlStreamWriter方式。