使用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
等部件,设计界面如下图所示。
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(
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"); }
下面运行程序,查找操作结果如下图所示。
然后对编号为1
的图书进行更新,效果如下图所示。
更新后我们再次查看所有内容。如下图所示。
然后进行删除操作,如下图所示。
删除后再次查询所有内容。效果如下图所示。
结语
通过本节的例子可以看到使用DOM可以很方便的进行XML文档的随机访问,这也是它最大的优点。关于更多更详细的内容可以参考《Qt Creator快速入门》的相关章节。
涉及到的源码: myDom_2.zip |