加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

QT中如何实现XML文件的创建、增加、修改、删除功能。

(2016-04-20 23:03:54)
标签:

qdomdocument

it

分类: QT

一、首先咱们得认识处理XML的方法有那些,QT提供了那些函数用于处理。

 

                     我们知道对XML的操作有两种方法,即DOM方式和SAX方式。二者主要区别是:DOM实现方式操作非常简单,但不适合处理过大文件;而SAX实现方式是能处理很大的XML文件,但是需要开发者写一些复杂的代码。Qt提供了对应于这两种用于读取、操作和编写XML的实现类,分别是QDomDocument类和QXmlStreamReader类,由于在项目中涉及的文件不大,因此我们选用QDomDocument类来

处理。

 

二、咱们需要了解XML文件的最常见格式:

 

         1、需要知道一个XML文件有且只有一个根节点;

         2、子节点与元素的概念,以及它们之间的联系(如何包含);

 

 

三、对XML文件创建,读取、修改:

 

 

1. 创建节点,将其写入XML文件,主要操作包括:

 

 


QDomDocument doc;

1).创建根节点:QDomElement root = doc.createElement_x("root")

2).创建元素节点:QDomElement element = doc.createElement_x("nodeName");

3).添加元素节点到根节点:root. appendChild(element);

4).创建元素文本:QDomText nodeText=doc.createTextNode("text");

5).添加元素文本到元素节点:element. appendChild(nodeText);

 

在本项目中,假设便签的属性有序号、名字、内容、字体、字号、颜色、粗细、斜体、下划线这几项,则在文件中添加一个便签节点的操作如下:

QDomDocument doc;

instruction = doc.createProcessingInstruction("xml","version="1.0" encoding="UTF-8"");

doc.appendChild(instruction);

QDomElement root = doc.createElement_x_x_x("Notes");

doc.appendChild(root);

QDomElement note = doc.createElement_x_x_x("note");

root.appendChild(note);

QDomElement no = doc.createElement_x_x_x("no");

note.appendChild(no);

...

...

QDomText no_text = doc.createTextNode("001");

...

...

则得到一个便签节点,将其保存到test.xml文件中,代码如下:

QFile file("test.xml");

if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate |QIODevice::Text))

return ;

QTextStream out(&file);

out.setCodec("UTF-8");

doc.save(out,4,QDomNode::EncodingFromTextStream);

file.close();

则test.xml文件:

 

 

 

001

2010-05-10(13:53:24)

A meeting!

Script MT Bold

16

#00ffff

0

true

true

 

 

上面是创建一个便签节点,若要继续添加便签节点,则需要在已有节点后增加一个新节点,并重写入XML文件。

 

2. 加载、查找便签时要读取XML文档中的节点信息,DOM实现方式是将整个文档当作一个对象来装入内存进行处理,然后开发者可以访问这个对象中的每一个节点,每一个节点对应XML文件里的一个标记。

 

主要操作包括:

1).读取根节点:QDomElement root = doc.documentElement();

2).读取第一个子节点:QDomNode node = root.firstChild();

3).读取下一个子节点:node = node.nextSibling();

4).匹配结点标记:node.toElement().tagName() == "note"

5).读取节点文本:no = childNode.toText().data();
//========================遍历节点================
可以通过doc.childNodes()获得doc的所有的子节点列表QDomNodeList。比如

QDomNodeList list=doc.childNodes();

for(int i=0;i

QDomNode node=list.at(i);//好的风格当然是把定义写在外面:(

//qDebug()<<”node name is “<<node.nodeName();

//qDebug()<<”node type is “<<.nodeType();

}
//==============================================

以下是项目中读取便签属性的函数实现代码:

void MainWindow::parseAttr(const QDomElement &element)

{

QString no,name,content,font,fontSize,color;

QDomNode node = element.firstChild();

while (!node.isNull()) {

if (node.toElement().tagName() == "note") {//匹配note节点

parseAttr(node.toElement());

} else if (node.toElement().tagName() == "no") {//匹配属性no

QDomNode childNode = node.firstChild();

if (childNode.nodeType() == QDomNode::TextNode) {

no = childNode.toText().data();

}

}

else if (node.toElement().tagName() == "name") //匹配属性name

...

...

node = node.nextSibling();//读取兄弟节点

}

}

3. 删除便签时,要删除相应的XML节点,用到的主要函数为:root.removeChild(node); 但在删除某个节点后要重写整个文件。

            以上对XML文件的重写操作是必须的,因此在文件的打开方式中要加上QIODevice::Truncate,表示覆盖重写。目前还没有找到可以直接修改文件的方法,但若文件很大的情况下,必须考虑相

应的效率问题。

 

 


4.读取XML文件内容:
//===================打开document===============add me ======
 QString xmlPath = "filename.xml";
 QFile file(xmlPath);
 if (!file.open(QFile::ReadOnly | QFile::Text))
  return ;

 QString errorStr;
 int errorLine;
 int errorColumn;

 QDomDocument doc;
 if (!doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn))
  return ;
 file.close();
//也可以用doc.setContent(&file)带一个参数就行。
//=============================================================

然后按照上面方式遍历数据,修改后在以上面相同的方式写入到XML文件中。


//=========================================附加一段代码创建XML文件===============

 

 

#include
#include
#include
#include
#include
#include
int main (int argc,char **argv)
{
     QApplication a (argc,argv);
     QFile file("InitInfo.xml");
  if(!file.open(QFile::ReadOnly | QFile::Text))
  {
     // QMessageBox::information(this,tr("error"),tr("无法打开XML文件"));
      return 1; 
  }
   

   QDomDocument doc;

   doc.setContent(&file,false,&errorStr,&errorLine,&errorColumn);
   file.close();

 
   QDomElement root = doc.createElement_x("root");     //创建根节点

 

 
  QDomElement element = doc.createElement_x("device3");     //创建第一个子节点

  element.setAttribute("ChildName","Content");

  QDomElement el_address = doc.createElement_x("Content");  //创建一个元素 该元素有三种属性
  el_address.setAttribute("key","equipmentname");
  el_address.setAttribute("value","CSC101B");
  el_address.setAttribute("name","itemName");

  element.appendChild(el_address);                       //将该元素增加到第一节点中.

  QDomElement el_path = doc.createElement_x("path");       //创建第二个元素,
  QDomText text_path = doc.createTextNode("aaa");         //创建该元素的文本
  el_path.appendChild(text_path);                        //将该元素文本增加到该元素中

  element.appendChild(el_path);                         //将该元素添加到第一个子节点中

  root.appendChild(element);                           //将该子节点加入到根节点下.


 QFile f("InitInfo.xml");
 if(!f.open(QFile::WriteOnly | QFile::Text))
  return 1;
  QTextStream out(&f);
  QTextCodec * codec = QTextCodec::codecForName("gbk");        //此处是设置文件支持的编码格式

  out.setCodec(codec);


  QString strHead("version =1.0 encoding =GB2312" );

  doc.appendChild(doc.createProcessingInstruction("xml" ,strHead ));
  out << doc.toString();
  root.save(out,2);
  f.close();

  return 0;

}

 

其它内容:

1 首先对XML文件进行操作,打开文件。

这个其实就是对文件进行操作,可以把它直接定义为构造函数,在对对象进行初始化时完成。

TopoDataReader::TopoDataReader(const wstring &filePath):_filePath(filePath),_qDomDoc("mydocument"),_qFile(QString::fromStdWString(filePath))
{
 if (!_qFile.open(QIODevice::ReadOnly))
 {
  return;
 }

 if (!_qDomDoc.setContent(&_qFile))
 {
  _qFile.close();
  return;
 }
}

2 读取XML文件中的节点内容

假设XML文件格式如下

(1)

 

 

 

 

(2)

211.87.235.136

对于第一种情况,采用如下方法:

QDomElement docElem = _qDomDoc.documentElement();

QDomNode nodeswitch=docElem.elementsByTagName("switch ");//红色的为标签名

QDomElement elemnodeswitch=nodeswitch.toElement();

string snmpip=qPrintable(elemnodeswitch.attribute("snmpip"));//network的也是如此方法获取

对于第二种情况,采用如下方法:

直接调用text() API就可以了

string ip=qPrintable(elementnodeip.text());

但是,假设文件中有多个同样的节点,如下

 

 

 

 

这样用elementsByTagName("b")返回的就是一个childNodes()而不是一个单独的node了。

我们可以使用at()方法具体定位。

另外,我们还可以使用这样一种方法获取节点的值,假设XML文件如下

- +
前端主交换机

-
192.168.120.251

public@120
true
true
true
0
50.0
50.0
161
true
CZ-5_FA
topLeft

我们可以先获取switch节点,然后得到其childNodes(),于是就可以使用at()方法来获取下面的每个节点了(注:从0开始)

比如说,上面的那个ip节点就是nodeswitch.childNodes().at(3)。

这样做得好处就是不用担心重复的问题,只要你确定switch节点确定对了,底下的也就一定能确定了。

3 返回某个节点下子节点的个数

这个简单,也是直接调API

QDomElement docElem = _qDomDoc.documentElement();
QDomNode nodetagname=docElem.elementsByTagName(tagname).at(0);//假设有多个tagname此处选第一个
int num=nodetagname.childNodes().size();

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有