找回密码
 立即注册
收起左侧

第28篇Qt5之 XML(二)使用DOM创建和操作XML文档

0
回复
15695
查看
[复制链接]
累计签到:1608 天
连续签到:1 天
来源: 2017-8-20 22:05:47 显示全部楼层 |阅读模式
使用DOM创建和操作XML文档
版权声明

该文章原创于Qt开源社区(www.qter.org),作者yafeilinux,转载请注明出处!


导语

在上一节中我们用手写的方法建立了一个XML文档,并且用DOM的方法对其进行了读取。现在我们使用代码来创建那个XML文档,并且实现查找、更新、插入等操作。



环境:Windows 7 + Qt 5.8.0(包含Qt Creator 4.2.1



目录

一、创建文档
二、读取文档
三、添加节点
四、查找、删除、更新操作



正文


一、创建文档

1.新建Qt Widgets应用,项目名称为mydom2,基类选择QMainWindow,类名为MainWindow

2.完成后打开mydom2.pro,然后将第一行代码更改为:QT       += core  gui  xml并保存该文件。

3.双击mainwindow.ui进入设计模式,往界面上添加Push ButtonLabelLine EditList Widget等部件,设计界面如下图所示。




4.完成后,回到编辑模式打开mainwindow.cpp文件,先包含头文件:

  1. #include <QtXml>
复制代码
然后在构造函数中添加如下代码:

  1. QFile file("my.xml");

  2. // 只写方式打开,并清空以前的信息
  3. if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) return ;

  4. QDomDocument doc;
  5. QDomProcessingInstruction instruction;  //添加处理指令
  6. instruction = doc.createProcessingInstruction("xml",
  7.                          "version="1.0" encoding="UTF-8"");
  8. doc.appendChild(instruction);
  9. QDomElement root = doc.createElement("书库");
  10. doc.appendChild(root); //添加根元素

  11. // 添加第一个book元素及其子元素
  12. QDomElement book = doc.createElement("图书");
  13. QDomAttr id = doc.createAttribute("编号");
  14. QDomElement title = doc.createElement("书名");
  15. QDomElement author = doc.createElement("作者");
  16. QDomText text;
  17. id.setValue("1");
  18. book.setAttributeNode(id);
  19. text = doc.createTextNode("Qt");
  20. title.appendChild(text);
  21. text = doc.createTextNode("shiming");
  22. author.appendChild(text);
  23. book.appendChild(title);
  24. book.appendChild(author);
  25. root.appendChild(book);

  26. // 添加第二个book元素及其子元素
  27. book = doc.createElement("图书");
  28. id = doc.createAttribute("编号");
  29. title = doc.createElement("书名");
  30. author = doc.createElement("作者");
  31. id.setValue("2");
  32. book.setAttributeNode(id);
  33. text = doc.createTextNode("Linux");
  34. title.appendChild(text);
  35. text = doc.createTextNode("yafei");
  36. author.appendChild(text);
  37. book.appendChild(title);
  38. book.appendChild(author);
  39. root.appendChild(book);
  40. QTextStream out(&file);

  41. doc.save(out,4); // 将文档保存到文件,4为子元素缩进字符数
  42. file.close();
复制代码


       这里先使用QDomDocument类在内存中生成了一棵DOM树,然后调用save()函数利用QTextStream文本流将DOM树保存在了文件中。在生成DOM树时主要使用了createElement()等函数来生成各种节点,然后使用appendChild()将各个节点依次追加进去。


5.运行程序,可以看到在构建目录中生成了my.xml文件,可以双击查看该文件的内容,效果如下图所示。



二、读取文档

       下面我们读取整个文档的内容,并显示在List Widget部件上面,这里用的就是上一节讲到的内容。我们从设计模式进入“查看全部信息”按钮单击信号槽,更改如下:

  1. void MainWindow::on_pushButton_5_clicked()
  2. {
  3.     ui->listWidget->clear(); //先清空显示
  4.     QFile file("my.xml");
  5.     if (!file.open(QIODevice::ReadOnly)) return ;
  6.     QDomDocument doc;
  7.     if (!doc.setContent(&file))
  8.     {
  9.         file.close();
  10.         return ;
  11.     }
  12.    file.close();

  13.     //返回根节点及其子节点的元素标记名
  14.     QDomElement docElem = doc.documentElement();  //返回根元素
  15.     QDomNode n = docElem.firstChild();   //返回根节点的第一个子节点
  16.     while(!n.isNull())  //如果节点不为空
  17.     {
  18.         if (n.isElement()) //如果节点是元素
  19.         {
  20.             QDomElement e = n.toElement(); //将其转换为元素
  21.             ui->listWidget->addItem(e.tagName()
  22.                                            +e.attribute(tr("编号")));
  23.             QDomNodeList list = e.childNodes();
  24.             for(int i=0; i<list.count(); i++)
  25.             {
  26.                 QDomNode node = list.at(i);
  27.                 if(node.isElement())
  28.                     ui->listWidget->addItem("   "
  29.                                     +node.toElement().tagName()
  30.                                     +" : "+node.toElement().text());
  31.             }
  32.         }
  33.         n = n.nextSibling();  //下一个兄弟节点
  34.     }
  35. }
复制代码


       运行程序,效果如下图所示。



三、添加节点


1.首先在设计模式,把书名和作者标签后面的Line Edit部件的objectName分别更改为lineEdit_titlelineEdit_author。如下图所示。




2.然后进入添加按钮的单击信号槽,添加如下代码:

  1. void MainWindow::on_pushButton_4_clicked()
  2. {
  3.     //我们先清空显示,然后显示“无法添加!”
  4.     ui->listWidget->clear();
  5.     ui->listWidget->addItem(tr("无法添加!"));
  6.     QFile file("my.xml");
  7.     if (!file.open(QIODevice::ReadOnly)) return;
  8.     QDomDocument doc;
  9.     if (!doc.setContent(&file))
  10.     {
  11.         file.close();
  12.         return;
  13.     }
  14.     file.close();
  15.     QDomElement root = doc.documentElement();
  16.     QDomElement book = doc.createElement("图书");
  17.     QDomAttr id = doc.createAttribute("编号");
  18.     QDomElement title = doc.createElement("书名");
  19.     QDomElement author = doc.createElement("作者");
  20.     QDomText text;
  21.    
  22.     // 我们获得了最后一个孩子结点的编号,然后加1,便是新的编号
  23.     QString num = root.lastChild().toElement().attribute("编号");
  24.     int count = num.toInt() +1;
  25.     id.setValue(QString::number(count));
  26.     book.setAttributeNode(id);
  27.    
  28.     text = doc.createTextNode(ui->lineEdit_title->text());
  29.     title.appendChild(text);
  30.    
  31.     text = doc.createTextNode(ui->lineEdit_author->text());
  32.     author.appendChild(text);
  33.    
  34.     book.appendChild(title);
  35.     book.appendChild(author);
  36.     root.appendChild(book);
  37.    
  38.     if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
  39.         return ;
  40.     QTextStream out(&file);
  41.     doc.save(out,4);   //将文档保存到文件,4为子元素缩进字符数
  42.     file.close();
  43.     ui->listWidget->clear(); //最后更改显示为“添加成功!”
  44.     ui->listWidget->addItem(tr("添加成功!"));
  45. }
复制代码


这里先用只读方式打开XML文件,将其读入doc中,然后关闭。我们将新的节点加入到最后面,并使其“编号”为以前的最后一个节点的编号加1。最后我们再用只写的方式打开XML文件,将修改完的doc写入其中。运行程序,效果如下图所示。




       再次查看全部信息,可以看到新的节点已经添加了,如下图所示。




四、查找、删除、更新操作

因为这三个功能都要先利用“编号”进行查找,所以我们放在一起实现。

1.首先将界面上“图书编号”后面的Line Edit部件的objectName更改为lineEdit_id


2.mainwindow.h文件中添加public类型的函数声明:
  
  1.   void doXml(const QString operate);
复制代码

我们使用这个函数来完成三种不同的操作,根据参数来判断不同的操作。


3.然后到mainwindow.cpp中添加该函数的定义:

  1. void MainWindow::doXml(const QString operate)
  2. {
  3.     ui->listWidget->clear();
  4.     ui->listWidget->addItem(tr("没有找到相关内容!"));
  5.     QFile file("my.xml");
  6.     if (!file.open(QIODevice::ReadOnly)) return ;
  7.     QDomDocument doc;
  8.     if (!doc.setContent(&file))
  9.     {
  10.         file.close();
  11.         return ;
  12.     }
  13.   file.close();

  14.     QDomNodeList list = doc.elementsByTagName("图书");
  15.     // 以标签名进行查找
  16.     for(int i=0; i<list.count(); i++)
  17.     {
  18.         QDomElement e = list.at(i).toElement();

  19.         // 如果元素的“编号”属性值与我们所查的相同
  20.         if(e.attribute("编号") == ui->lineEdit_id->text())
  21.         {
  22.             // 如果元素的“编号”属性值与我们所查的相同
  23.             if(operate == "delete")  //如果是删除操作
  24.             {
  25.                 QDomElement root = doc.documentElement(); //取出根节点
  26.                 root.removeChild(list.at(i));  //从根节点上删除该节点
  27.                 QFile file("my.xml");     //保存更改
  28.            if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
  29.                 return ;
  30.                 QTextStream out(&file);
  31.                 doc.save(out,4);
  32.                 file.close();
  33.                 ui->listWidget->clear();
  34.                 ui->listWidget->addItem(tr("删除成功!"));
  35.             }

  36.             else if(operate == "update")  //如果是更新操作
  37.             {
  38.                 QDomNodeList child = list.at(i).childNodes();
  39.                 //找到它的所有子节点,就是“书名”和“作者”
  40.                 child.at(0).toElement().firstChild().setNodeValue(
  41.                                                                ui->lineEdit_title->text());
  42.                 //将它子节点的首个子节点(就是文本节点)的内容更新
  43.                 child.at(1).toElement().firstChild().setNodeValue(
  44.                                                          ui->lineEdit_author->text());
  45.                 QFile file("my.xml");     //保存更改
  46.            if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
  47.                 return ;
  48.                 QTextStream out(&file);
  49.                 doc.save(out,4);   //保存文档,4为子元素缩进字符数
  50.                 file.close();
  51.                 ui->listWidget->clear();
  52.                 ui->listWidget->addItem(tr("更新成功!"));
  53.             }

  54.             else if(operate == "find")  //如果是查找操作
  55.             {
  56.                 ui->listWidget->clear();
  57.                 ui->listWidget->addItem(e.tagName()
  58.                                                +e.attribute(tr("编号")));
  59.                 QDomNodeList list = e.childNodes();
  60.                 for(int i=0; i<list.count(); i++)
  61.                 {
  62.                     QDomNode node = list.at(i);
  63.                     if(node.isElement())
  64.                         ui->listWidget->addItem("   "
  65.                                  +node.toElement().tagName()
  66.                                  +" : "+node.toElement().text());
  67.                 }
  68.             }
  69.         }
  70.     }
  71. }
复制代码


4. 下面我们分别进入查找删除更新三个按钮的单击信号槽,更改如下:

  1. // 查找
  2. void MainWindow::on_pushButton_clicked()
  3. {
  4.     doXml("find");
  5. }

  6. // 删除
  7. void MainWindow::on_pushButton_2_clicked()
  8. {
  9.     doXml("delete");
  10. }

  11. // 更新
  12. void MainWindow::on_pushButton_3_clicked()
  13. {
  14.     doXml("update");
  15. }
复制代码

下面运行程序,查找操作结果如下图所示。




然后对编号为1的图书进行更新,效果如下图所示。




更新后我们再次查看所有内容。如下图所示。




然后进行删除操作,如下图所示。




删除后再次查询所有内容。效果如下图所示。





结语


通过本节的例子可以看到使用DOM可以很方便地进行XML文档的随机访问,这也是它最大的优点。关于更多更详细的内容可以参考《QtCreator快速入门》的相关章节。

源码下载:



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了