yafeilinux 发表于 2013-5-21 22:00:51

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

使用DOM创建和操作XML文档
版权声明该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处!

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

环境:Windows Xp + Qt 4.8.4+QtCreator 2.6.2

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

正文
一、创建文档
1.新建Qt Gui应用,项目名称为myDom_2,基类为QMainWindow,类名为MainWindow。
2.完成后打开myDom_2.pro,然后将第一行代码更改为:QT       += coregui   xml       保存该文件。
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(tr("书库"));doc.appendChild(root); //添加根元素
// 添加第一个book元素及其子元素QDomElement book = doc.createElement(tr("图书"));QDomAttr id = doc.createAttribute(tr("编号"));QDomElement title = doc.createElement(tr("书名"));QDomElement author = doc.createElement(tr("作者"));QDomText text;id.setValue(tr("1"));book.setAttributeNode(id);text = doc.createTextNode(tr("Qt"));title.appendChild(text);text = doc.createTextNode(tr("shiming"));author.appendChild(text);book.appendChild(title);book.appendChild(author);root.appendChild(book);
// 添加第二个book元素及其子元素book = doc.createElement(tr("图书"));id = doc.createAttribute(tr("编号"));title = doc.createElement(tr("书名"));author = doc.createElement(tr("作者"));id.setValue(tr("2"));book.setAttributeNode(id);text = doc.createTextNode(tr("Linux"));title.appendChild(text);text = doc.createTextNode(tr("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.打开main.cpp文件,先包含头文件:#include <QTextCodec>,然后在main()函数第一行代码后面添加如下代码:QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));

6.运行程序,可以看到在构建目录中生成了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(tr("图书"));    QDomAttr id = doc.createAttribute(tr("编号"));    QDomElement title = doc.createElement(tr("书名"));    QDomElement author = doc.createElement(tr("作者"));    QDomText text;     // 我们获得了最后一个孩子结点的编号,然后加1,便是新的编号    QString num = root.lastChild().toElement().attribute(tr("编号"));    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(constQString 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(tr("图书"));    // 以标签名进行查找    for(int i=0; i<list.count(); i++)    {       QDomElement e = list.at(i).toElement();        // 如果元素的“编号”属性值与我们所查的相同       if(e.attribute(tr("编号")) == 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文档的随机访问,这也是它最大的优点。关于更多更详细的内容可以参考《Qt Creator快速入门》的相关章节。

涉及到的源码:


上一篇:第27篇 XML(一)使用DOM读取XML文档

下一篇: 第29篇 XML(三)Qt中的SAX

返回:系列教程目录

zhang206zyx 发表于 2014-3-31 17:20:38

:Q按照这个设置,最后中文各种乱码,是在不知道怎么回事了

yafeilinux 发表于 2014-4-6 09:09:24

zhang206zyx 发表于 2014-3-31 17:20 static/image/common/back.gif
按照这个设置,最后中文各种乱码,是在不知道怎么回事了

可能是Qt版本问题。你用那个版本?

zhang206zyx 发表于 2014-4-7 00:08:05

yafeilinux 发表于 2014-4-6 09:09 static/image/common/back.gif
可能是Qt版本问题。你用那个版本?

4.8.5 win7,现在感觉和源代码的编码也有关系,如果设置的是GBK而不是UTF-8的话。

yafeilinux 发表于 2014-4-8 18:55:59

zhang206zyx 发表于 2014-4-7 00:08 static/image/common/back.gif
4.8.5 win7,现在感觉和源代码的编码也有关系,如果设置的是GBK而不是UTF-8的话。 ...

嗯,是编码的问题,下载上面的源码试试。

lyzyung 发表于 2014-4-18 14:35:03

图书后面的编号显示不出来

yafeilinux 发表于 2014-4-20 22:48:03

lyzyung 发表于 2014-4-18 14:35 static/image/common/back.gif
图书后面的编号显示不出来

是运行的源码吗?

lyzyung 发表于 2014-4-21 16:08:33

yafeilinux 发表于 2014-4-20 22:48 static/image/common/back.gif
是运行的源码吗?

不是现在能显示出来了

胃小饱 发表于 2014-7-4 17:16:21

本帖最后由 胃小饱 于 2014-7-4 17:39 编辑

yafeil老师,我的IE读my.xml,不能正常显示,是不是需要设置什么地方?显示如下:

无法显示 XML 页。
使用 样式表无法查看 XML 输入。请更正错误然后单击 刷新按钮,或以后重试。


--------------------------------------------------------------------------------

预期会有空格或 '?'。处理资源 'file:///E:/Qtstudy/build-myDom_2-Desktop_Qt_5_3_MinGW_32bit-Debug/my.xml' 时出错。第 1 行,位置: 20





呃呃呃...我在encoding前 加了个空格,能正常显示了...   不好意思 ,多发了个帖子。。

oudiqianbi 发表于 2014-10-22 21:02:31

我QT4.7.4,creactor2.2.0 ,上边代码编译出来的XML是乱码,下载源文件里的中文注释是乱码。把汉字编码和XML文件的编码都设置为GBK就可以了

oudiqianbi 发表于 2014-10-23 10:47:58

学习XML这几章发现了编码存在问题,特意贴上一个QT编码设置的方法http://blog.csdn.net/leo115/article/details/7533463

yqiaoi 发表于 2015-11-23 11:26:51

为什么生成的my.xml稳当打开后 内容都在一行显示 看着很别扭啊

yafeilinux 发表于 2015-11-23 23:41:14

yqiaoi 发表于 2015-11-23 11:26 static/image/common/back.gif
为什么生成的my.xml稳当打开后 内容都在一行显示 看着很别扭啊

用写字板打开试试。

yqiaoi 发表于 2015-11-24 08:27:22

yafeilinux 发表于 2015-11-23 23:41 static/image/common/back.gif
用写字板打开试试。

写字板打开 汉字都是乱码 记事本打开不乱码只是都在一行 读写操作倒是都正常 然后用后面的流来写的xml文档也是正常的 用dom写xml(也就是本章说的方法)才会有记事本打开都在一行的现象

yafeilinux 发表于 2015-11-30 17:31:26

yqiaoi 发表于 2015-11-24 08:27 static/image/common/back.gif
写字板打开 汉字都是乱码 记事本打开不乱码只是都在一行 读写操作倒是都正常 然后用后面的流来写的xml文 ...

乱码应该是编码设置问题。

QtRookie 发表于 2016-1-2 15:46:00

老师您好!在添加节点中的setContent函数返回false值,应该怎么解决?

yafeilinux 发表于 2016-1-2 20:31:04

QtRookie 发表于 2016-1-2 15:46 static/image/common/back.gif
老师您好!在添加节点中的setContent函数返回false值,应该怎么解决?

这个得具体问题具体分析啊,自己先调试找下原因吧。

QtRookie 发表于 2016-1-3 10:30:03

yafeilinux 发表于 2016-1-2 20:31 static/image/common/back.gif
这个得具体问题具体分析啊,自己先调试找下原因吧。

看到上一篇那里,说xml文件开头那一行的encoding要加空格,果然是这个问题。我是自己写的程序,所以没有注意到这个问题。

牛亚灰 发表于 2016-4-2 14:51:41

yqiaoi 发表于 2015-11-24 08:27 static/image/common/back.gif
写字板打开 汉字都是乱码 记事本打开不乱码只是都在一行 读写操作倒是都正常 然后用后面的流来写的xml文 ...

我也遇到了这个问题,请问您是怎么解决的?

huihuiyu 发表于 2016-7-20 09:49:50

感觉好复杂,特别是有遍历的部分
页: [1] 2
查看完整版本: 第28篇 XML(二)使用DOM创建和操作XML文档