全部博文(59)
分类: C/C++
2011-08-26 10:22:26
本文章原创于 转载请注明出处。
我们把XML放到数据库部分来讲,因为XML与数据库有着千丝万缕的联系,这里我们不再对XML进行过多的介绍,如果你还没有接触过它,可以在网上搜索一下关键字,其实对于我们下面讲述的内容,即便你不知道什么是XML,你也会很快掌握的。
在Qt中提供了QtXml模块实现了对XML数据的处理,我们在Qt帮助中输入关键字QtXml Module,可以看到该模块的类表。
在这里我们可以看到所有相关的类,它们主要是服务于两种操作XML文档的方法:DOM和SAX。Dom(Document Object Model,即文档对象模型)把XML文档转换成应用程序可以遍历的树形结构,这样便可以随机访问其中的节点。它的缺点是需要将整个XML文档读入内存,消耗内存较多。对于SAX我们放到后面再讲。
除了上面的两种方法外,Qt还提供了简单的QXmlStreamReader和QXmlStreamWriter对XML文档进行读写。
下面我们先介绍使用DOM的方式来操作XML文档。
下面是一个规范的XML文档:
//XML说明
//结束标记名
(我们为了讲述方便使用了//注释,其实XML文档中是没有这些注释的)
可以看到,一个规范的XML文档,是用XML说明开始的,主要由各元素组成。XML文档第一个元素就是根元素,XML文档必须有且只有一个根元素。元素是可以嵌套的。
下面我们就使用程序读出该文档中所有信息。
在Qt Creator中新建控制台工程Qt4 Console Application,工程名为xml01,在选择模块页选中QtXml(如果在这里没有添加,就需要在工程文件中手动添加QT += xml ;在新版本的Qt Creator中可能没有模块添加页,只能在对应的.pro文件中手动添加)。
下面我们更改main.cpp的内容如下:
#include
#include
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QDomDocument doc; //新建QDomDocument类对象,它代表一个XML文档
QFile file(“my.xml”); //建立指向“my.xml”文件的QFile对象
if (!file.open(QIODevice::ReadOnly)) return 0; //以只读方式打开
if (!doc.setContent(&file)) { file.close(); return 0; }
//将文件内容读到doc中
file.close();
//关闭文件
QDomNode firstNode = doc.firstChild(); //获得doc的第一个节点,即XML说明
qDebug() << firstNode.nodeName() //输出XML说明
<< firstNode.nodeValue();
return a.exec();
}
我们先运行一下程序。然后在工程文件夹的debug文件夹下单击鼠标右键,新建文本文档,改名为“my.xml”,这里一定要注意把原来的“.txt”后缀改为“.xml”(注:在新版的Qt Creator中可能需要将文件放在xml01-build-desktop文件夹中) 。然后我们利用记事本打开该文件,并将上面的XML文档的信息写入其中,不要写注释信息,然后保存。
再次运行程序,效果如下:
我们不愿意让输出信息出现双引号,可以更改程序代码:
qDebug() << qPrintable(firstNode.nodeName()) //输出XML说明
<< qPrintable(firstNode.nodeValue());
这里利用了qPrintable()函数。
效果如下:
下面我们在return a.exec();代码前继续添加代码:
QDomElement docElem = doc.documentElement(); //返回根元素
QDomNode n = docElem.firstChild(); //返回根节点的第一个子节点
while(!n.isNull())
{ //如果节点不为空
if (n.isElement()) //如果节点是元素
{
QDomElement e = n.toElement(); //将其转换为元素
qDebug() << qPrintable(e.tagName()) //返回元素标记
<< qPrintable(e.attribute(“id”)); //返回元素id属性的值
}
n = n.nextSibling(); //下一个兄弟节点
}
这样便能输出根元素及其子元素了。我们这里使用了firstChild()函数和nextSibling()函数,然后利用while()循环来实现对所有子元素的遍历。运行结果如下:
下面我们更改if()语句中的代码,用另一种方法遍历book元素的所有子元素。
if (n.isElement()) //如果节点是元素
{
QDomElement e = n.toElement(); //将其转换为元素
qDebug() << qPrintable(e.tagName()) //返回元素标记
<< qPrintable(e.attribute(“id”)); //返回元素id属性的值
QDomNodeList list = e.childNodes(); //获得元素e的所有子节点的列表
for(int i=0; i { QDomNode node = list.at(i); if(node.isElement()) qDebug() << “ “<< qPrintable(node.toElement().tagName()) < } } 这里使用了childNodes()函数获得了元素所有子节点的列表,然后通过遍历这个列表实现了遍历其所有子元素。运行程序,效果如下: 小结:通过上面的例子,我们实现了对一个XML文档的读取。可以看到,在QDom中,是将整个XML文件读到内存中的doc对象中的。然后使用节点(QDomNode )操作doc对象,像XML说明,元素,属性,文本等等都被看做是节点,这样就使得操作XML文档变得很简单,我们只需通过转换函数将节点转换成相应的类型,如 QDomElement e = n.toElement(); 在下一节我们将讲述XML文件的创建和写入。