[Qt教程] 第28篇 XML(二)使用DOM创建和操作XML文档

楼主

图片[1]-[Qt教程] 第28篇 XML(二)使用DOM创建和操作XML文档-卡核 
发表于 2013-5-21 22:00:51 
| 查看: 475
| 回复: 0

使用DOM创建和操作XML文档

版权声明


该文章原创于作者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
       += core  gui   xml
       
保存该文件。

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

28-1.jpg

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
文件,可以双击查看该文件的内容,效果如下图所示。

28-2.jpg
二、读取文档
       
下面我们读取整个文档的内容,并显示在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();
  
//
下一个兄弟节点
    
}
}

       
运行程序,效果如下图所示。
28-3.jpg
三、添加节点

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

28-4.jpg 

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写入其中。运行程序,效果如下图所示。

28-5.jpg

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

28-6.jpg
四、查找、删除、更新操作
因为这三个功能都要先利用“编号”进行查找,所以我们放在一起实现。

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(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");
}

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

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

28-8.jpg

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

28-9.jpg
然后进行删除操作,如下图所示。
28-10.jpg
删除后再次查询所有内容。效果如下图所示。

28-11.jpg
结语


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


涉及到的源码:  myDom_2.zip (4.21 KB, 下载次数: 12) 


© 版权声明
THE END
喜欢就支持一下吧
点赞137 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容