yafeilinux 发表于 2017-8-20 22:05:47

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

使用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       += coreguixml并保存该文件。
3.双击mainwindow.ui进入设计模式,往界面上添加Push Button,Label,Line Edit,List Widget等部件,设计界面如下图所示。



4.完成后,回到编辑模式打开mainwindow.cpp文件,先包含头文件:
#include <QtXml>然后在构造函数中添加如下代码:
QFile file("my.xml");

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

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

// 添加第一个book元素及其子元素
QDomElement book = doc.createElement("图书");
QDomAttr id = doc.createAttribute("编号");
QDomElement title = doc.createElement("书名");
QDomElement author = doc.createElement("作者");
QDomText text;
id.setValue("1");
book.setAttributeNode(id);
text = doc.createTextNode("Qt");
title.appendChild(text);
text = doc.createTextNode("shiming");
author.appendChild(text);
book.appendChild(title);
book.appendChild(author);
root.appendChild(book);

// 添加第二个book元素及其子元素
book = doc.createElement("图书");
id = doc.createAttribute("编号");
title = doc.createElement("书名");
author = doc.createElement("作者");
id.setValue("2");
book.setAttributeNode(id);
text = doc.createTextNode("Linux");
title.appendChild(text);
text = doc.createTextNode("yafei");
author.appendChild(text);
book.appendChild(title);
book.appendChild(author);
root.appendChild(book);
QTextStream out(&file);

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

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

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


二、读取文档
       下面我们读取整个文档的内容,并显示在List Widget部件上面,这里用的就是上一节讲到的内容。我们从设计模式进入“查看全部信息”按钮单击信号槽,更改如下:
void MainWindow::on_pushButton_5_clicked()
{
    ui->listWidget->clear(); //先清空显示
    QFile file("my.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(); //将其转换为元素
            ui->listWidget->addItem(e.tagName()
                                           +e.attribute(tr("编号")));
            QDomNodeList list = e.childNodes();
            for(int i=0; i<list.count(); i++)
            {
                QDomNode node = list.at(i);
                if(node.isElement())
                  ui->listWidget->addItem("   "
                                    +node.toElement().tagName()
                                    +" : "+node.toElement().text());
            }
      }
      n = n.nextSibling();//下一个兄弟节点
    }
}

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


三、添加节点

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



2.然后进入添加按钮的单击信号槽,添加如下代码:
void MainWindow::on_pushButton_4_clicked()
{
    //我们先清空显示,然后显示“无法添加!”
    ui->listWidget->clear();
    ui->listWidget->addItem(tr("无法添加!"));
    QFile file("my.xml");
    if (!file.open(QIODevice::ReadOnly)) return;
    QDomDocument doc;
    if (!doc.setContent(&file))
    {
      file.close();
      return;
    }
    file.close();
    QDomElement root = doc.documentElement();
    QDomElement book = doc.createElement("图书");
    QDomAttr id = doc.createAttribute("编号");
    QDomElement title = doc.createElement("书名");
    QDomElement author = doc.createElement("作者");
    QDomText text;
   
    // 我们获得了最后一个孩子结点的编号,然后加1,便是新的编号
    QString num = root.lastChild().toElement().attribute("编号");
    int count = num.toInt() +1;
    id.setValue(QString::number(count));
    book.setAttributeNode(id);
   
    text = doc.createTextNode(ui->lineEdit_title->text());
    title.appendChild(text);
   
    text = doc.createTextNode(ui->lineEdit_author->text());
    author.appendChild(text);
   
    book.appendChild(title);
    book.appendChild(author);
    root.appendChild(book);
   
    if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
      return ;
    QTextStream out(&file);
    doc.save(out,4);   //将文档保存到文件,4为子元素缩进字符数
    file.close();
    ui->listWidget->clear(); //最后更改显示为“添加成功!”
    ui->listWidget->addItem(tr("添加成功!"));
}

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



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



四、查找、删除、更新操作
因为这三个功能都要先利用“编号”进行查找,所以我们放在一起实现。
1.首先将界面上“图书编号”后面的Line Edit部件的objectName更改为lineEdit_id。

2.在mainwindow.h文件中添加public类型的函数声明:void doXml(const QString operate);
我们使用这个函数来完成三种不同的操作,根据参数来判断不同的操作。

3.然后到mainwindow.cpp中添加该函数的定义:
void MainWindow::doXml(const QString operate)
{
    ui->listWidget->clear();
    ui->listWidget->addItem(tr("没有找到相关内容!"));
    QFile file("my.xml");
    if (!file.open(QIODevice::ReadOnly)) return ;
    QDomDocument doc;
    if (!doc.setContent(&file))
    {
      file.close();
      return ;
    }
file.close();

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

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

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

            else if(operate == "find")//如果是查找操作
            {
                ui->listWidget->clear();
                ui->listWidget->addItem(e.tagName()
                                             +e.attribute(tr("编号")));
                QDomNodeList list = e.childNodes();
                for(int i=0; i<list.count(); i++)
                {
                  QDomNode node = list.at(i);
                  if(node.isElement())
                        ui->listWidget->addItem("   "
                                 +node.toElement().tagName()
                                 +" : "+node.toElement().text());
                }
            }
      }
    }
}

4. 下面我们分别进入“查找”,“删除”,“更新”三个按钮的单击信号槽,更改如下:
// 查找
void MainWindow::on_pushButton_clicked()
{
    doXml("find");
}

// 删除
void MainWindow::on_pushButton_2_clicked()
{
    doXml("delete");
}

// 更新
void MainWindow::on_pushButton_3_clicked()
{
    doXml("update");
}
下面运行程序,查找操作结果如下图所示。



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



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



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



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




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

页: [1]
查看完整版本: 第28篇Qt5之 XML(二)使用DOM创建和操作XML文档