首页 > 代码库 > Qt XML的使用

Qt XML的使用

Qt中对于XML文件的写入有两种方式,一个是使用QXmlStreamWriter,另一个则为使用Dom。stream流的形式相对来说更加灵活,而且适合处理大文件。Dom方式由于是将内容加载到了内存中进行操作,所以对于小内存设备则有一定得局限性。

根据《QtCreator快速入门》和网上的一些例子练习了Qt XML的使用,做一个记录,以下是采用Dom方式实现的

实现界面

编写的XML文件

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <information>
 3     <pin id="1">
 4         <card id="1">
 5             <port id="1" flag="0"/>
 6             <port id="2" flag="0"/>
 7             <port id="3" flag="0"/>
 8             <port id="4" flag="0"/>
 9             <port id="5" flag="0"/>
10             <port id="6" flag="0"/>
11             <port id="7" flag="0"/>
12         </card>
13         <card id="2">
14             <port id="1" flag="0"/>
15             <port id="2" flag="0"/>
16             <port id="3" flag="0"/>
17             <port id="4" flag="0"/>
18             <port id="5" flag="0"/>
19             <port id="6" flag="0"/>
20         </card>
21         <card id="3">
22             <port id="1" flag="0"/>
23             <port id="2" flag="0"/>
24             <port id="3" flag="0"/>
25             <port id="4" flag="0"/>
26             <port id="5" flag="0"/>
27         </card>
28     </pin>
29     <pin id="2">
30         <card id="1">
31             <port id="1" flag="0"/>
32             <port id="2" flag="0"/>
33             <port id="3" flag="0"/>
34             <port id="4" flag="0"/>
35             <port id="5" flag="0"/>
36             <port id="6" flag="0"/>
37             <port id="7" flag="0"/>
38         </card>
39         <card id="2">
40             <port id="1" flag="0"/>
41             <port id="2" flag="0"/>
42             <port id="3" flag="0"/>
43             <port id="4" flag="0"/>
44             <port id="5" flag="0"/>
45             <port id="6" flag="0"/>
46         </card>
47     </pin>
48 </information>

一共有三层,pin->card->port,最内层的port有id和flag两种属性

首先是编写XML文件

代码如下:

 1 void xml::writeXML()
 2 {
 3     QFile file("../project/ini/write.xml");
 4     if(!file.open(QIODevice::WriteOnly|QIODevice::Truncate))
 5         {
 6         return;
 7     }
 8     QDomDocument doc;
 9     QDomProcessingInstruction instruction;
10 
11     instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
12     doc.appendChild(instruction);
13     QDomElement root=doc.createElement(tr("information"));
14     doc.appendChild(root);
15 
16     QDomElement Pin;
17     QDomElement Card;
18     QDomElement Port;
19     QDomAttr ID = doc.createAttribute("id");
20     QDomAttr Flag = doc.createAttribute("flag");
21     //QDomText text;
22 
23     for (int i = 1;i < 3;i++)
24     {
25         Pin = doc.createElement(tr("pin"));
26 
27         ID = doc.createAttribute("id");
28         ID.setValue(tr("%1").arg(i));
29         Pin.setAttributeNode(ID);
30 
31         //Pin.appendChild(Card);
32         //Card = doc.createElement(tr("card"));
33         for (int j = 1;j < 5 - i;j++)
34         {
35             Card = doc.createElement(tr("card"));
36 
37             ID = doc.createAttribute("id");
38             ID.setValue(tr("%1").arg(j));
39             Card.setAttributeNode(ID);
40 
41             for (int k = 1;k < 9 - j;k++)
42             {
43                 Port = doc.createElement(tr("port"));
44 
45                 ID = doc.createAttribute("id");
46                 ID.setValue(tr("%1").arg(k));
47                 Port.setAttributeNode(ID);
48                 Flag = doc.createAttribute("flag");
49                 Flag.setValue("0");
50                 Port.setAttributeNode(Flag);
51 
52                 Card.appendChild(Port);
53             }
54             Pin.appendChild(Card);
55         }
56         root.appendChild(Pin);
57     }
58 
59     QTextStream out(&file);
60     doc.save(out,4);
61     file.close();
62 }

QDomProcessingInstruction instruction;

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

用来写入XML文件的声明,这对于一个XML文件来说不可缺少。

writeXML()中采用三层for循环进行XML的存储。

好了,现在有我们需要操作的XML文件了,下一步就是就是进行读取,并在界面上显示
我是采用三个listWidget分别显示pin card port信息的
代码如下:
 1 /*
 2 *函数名:_CreateListWidget
 3 *功能:初始化探针、板卡、端口信息
 4 *
 5 */
 6 void configure_win::_CreateListWidget()
 7 {
 8     ui->cardlistWidget->clear();
 9     ui->portlistWidget->clear();
10     ui->pinlistWidget->clear();
11     int flag_card = 1;
12     int flag_port = 1;//判断标识,确定listWidget初始化显示一次
13     QDomDocument doc;
14     QFile file("../project/ini/write.xml");
15     if (!file.open(QIODevice::ReadOnly))
16     {
17         return;
18     }
19     if (!doc.setContent(&file))
20     {
21         file.close();
22         return;
23     }
24     file.close();
25     QDomElement docElem = doc.documentElement();
26     QDomNode n = docElem.firstChild();
27     while (!n.isNull())
28     {
29         if (n.isElement())
30         {
31             QDomElement e = n.toElement();
32             ui->pinlistWidget->addItem(e.toElement().tagName()+e.toElement().attribute("id"));
33             //ui->pinlistWidget->addItem("探针"+e.toElement().attribute("id"));
34             QDomNodeList listcard = e.childNodes();
35             if (flag_card)
36             {
37                 for (int i = 0;i < listcard.count();i++)
38                 {
39                     QDomNode node = listcard.at(i);
40                     if (node.isElement())
41                     {
42                         ui->cardlistWidget->addItem(node.toElement().tagName()+node.toElement().attribute("id"));
43                         //ui->cardlistWidget->addItem("板卡"+node.toElement().attribute("id"));
44                         QDomNodeList listport = node.childNodes();
45                         if (flag_port)
46                         {    for  (int j = 0;j < listport.count();j++)
47                             {
48                                 QDomNode port = listport.at(j);
49                                 if (port.isElement())
50                                 {
51                                     QListWidgetItem *item = new QListWidgetItem;
52                                     item->setText(port.toElement().tagName() + port.toElement().attribute("id"));
53                                     item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable);
54                                     item->setCheckState(Qt::Unchecked);
55                                     ui->portlistWidget->addItem(item);
56                                     //ui->portlistWidget->addItem(port.toElement().tagName() + port.toElement().attribute("id"));
57                                     //ui->portlistWidget->addItem("端口" + port.toElement().attribute("id"));
58                                 }
59                             }
60                         }
61                         flag_port = 0;
62                     }
63                     node = node.nextSibling();
64                 }
65             }
66             flag_card = 0;
67         }
68         n = n.nextSibling();
69     }
70     ui->pinlistWidget->item(0)->setSelected(true);
71     ui->cardlistWidget->item(0)->setSelected(true);
72     g_pin = ui->pinlistWidget->item(0)->text();//初始化存储pin card port
73     g_card = ui->cardlistWidget->item(0)->text();
74     g_port = ui->portlistWidget->item(0)->text();
75 }

因为涉及到获取listWidget的item的信息,而界面上只能有一个焦点,所以我使用了三个全局变量保存当前被激活的item项

并且默认为第一项被选中,这样就完成了开始界面的呈现

 

现在只是完成了XML数据的静态呈现,还没有动态显示,所以下一步需要对listWidget添加一些信号槽函数

1 connect(ui->pinlistWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(xmlChanged(QListWidgetItem*)));//点击探针
2     connect(ui->cardlistWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(xmlChanged(QListWidgetItem*)));//点击板卡

代码如下:

 1 /*
 2 *槽函数名:xmlChanged
 3 *功能:根据选择读取xml信息
 4 *
 5 */
 6 void configure_win::xmlChanged(QListWidgetItem *item)
 7 {
 8     QString str = item->text();
 9     QString str2 = str.right(1);//取最后一位1
10     QString str1 = str.left(str.length() - 1);//去掉最后一位 card
11     if (str1 == "pin")//点击pin
12     {
13         g_pin = str;//选中的pin改变
14         g_card = "card1";//默认card1
15         g_port = "port1";
16         _SelectChanged(str,"card1");
17         ui->cardlistWidget->item(0)->setSelected(true);
18     }
19     else if (str1 == "card")//点击card
20     {
21         g_card = str;//选中的card改变
22         g_port = "port1";
23         QString strpin;
24         if (ui->pinlistWidget->currentRow() == -1)//获得选中card对应探针????初始化pin第一项pin为选中,为什么返回-1而不是0
25         {
26             strpin = ui->pinlistWidget->item(0)->text();
27         }
28         else
29         {
30             strpin = ui->pinlistWidget->currentItem()->text();
31         }
32         int i = ui->cardlistWidget->currentRow();//获取选中card项
33         _SelectChanged(strpin,str);//更新listWidget
34         ui->cardlistWidget->item(i)->setSelected(true);//重新设置card为选中
35     }
36 }
 1 /*
 2 *函数名:_SelectChanged
 3 *功能:更新探针、板卡、端口信息
 4 *
 5 */
 6 void configure_win::_SelectChanged(QString str1, QString str2)
 7 {
 8 
 9     QDomDocument doc;
10     QFile file("../project/ini/write.xml");
11     if (!file.open(QIODevice::ReadOnly))
12     {
13         return;
14     }
15     if (!doc.setContent(&file))
16     {
17         file.close();
18         return;
19     }
20     file.close();
21 
22     //QString str = item->text();
23     //qDebug()<<str1;
24     QString strNumberPin = str1.right(1);
25     QString strTypePin = str1.left(str1.length() - 1);//去掉最后一位
26     QString strNumberCard = str2.right(1);
27     QString strTypeCard = str2.left(str1.length() - 1);//去掉最后一位
28     //qDebug()<<strNumberPin<<strTypePin<<strNumberCard<<"\n"<<strTypeCard;
29     //if (i)//点击板卡
30     {
31         QDomNodeList list = doc.elementsByTagName(strTypePin);//查找探针项
32         for (int i = 0;i < list.count();i++)
33         {
34             QDomElement e = list.at(i).toElement();
35             if (e.attribute("id") == strNumberPin)//找到对应的探针
36             {
37                 ui->cardlistWidget->clear();//清空板卡
38                 QDomNodeList childCard = e.childNodes();
39                 for (int j = 0;j < childCard.count();j++)//遍历板卡
40                 {
41                     QDomElement card = childCard.at(j).toElement();
42                     //QDomNode port = childCard.at(j);
43                     //qDebug()<<"      "<<qPrintable(card.tagName())<<qPrintable(card.attribute("id"));
44                     QListWidgetItem *item = new QListWidgetItem;
45                     item->setText(card.tagName() + card.attribute("id"));
46 
47                     //item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable);
48                     //item->setCheckState(Qt::Unchecked);
49                     ui->cardlistWidget->addItem(item);
50                     if (card.attribute("id") == strNumberCard)
51                     {
52                         ui->portlistWidget->clear();//清空端口
53                         QDomNodeList childPort = card.childNodes();
54 
55                         for (int k = 0;k < childPort.count();k++)
56                         {
57                             QDomNode port = childPort.at(k);
58                             //qDebug()<<"      "<<qPrintable(port.toElement().tagName())<<qPrintable(port.toElement().attribute("id"));
59                             QListWidgetItem *item = new QListWidgetItem;
60                             item->setText(port.toElement().tagName() + port.toElement().attribute("id"));
61                             item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable);
62                             if (port.toElement().attribute("flag") == "0")
63                             {
64                                 item->setCheckState(Qt::Unchecked);
65                             }
66                             else
67                             {
68                                 item->setCheckState(Qt::Checked);
69                             }
70                             ui->portlistWidget->addItem(item);
71                         }
72                     }
73                 }
74                 return;//完成部分显示后跳出遍历
75             }
76         }
77     }
78 }
xmlChanged()函数响应信号,获取item信息
_SelectChanged()函数根据pin,card读取XML进行界面的动态呈现,还是默认card、port的第一项为选中

到现在为止,我只进行了XML的读取(全部和选择部分),下面是进行XML的修改,这里我选择更改port的flag属性,默认为0,选中为1

 1 <?xml version=1.0 encoding=UTF-8?>
 2 <information>
 3     <pin id="1">
 4         <card id="1">
 5             <port id="1" flag="0"/>
 6             <port id="2" flag="0"/>
 7             <port id="3" flag="0"/>
 8             <port id="4" flag="0"/>
 9             <port id="5" flag="0"/>
10             <port id="6" flag="0"/>
11             <port id="7" flag="0"/>
12         </card>
13         <card id="2">
14             <port id="1" flag="0"/>
15             <port id="2" flag="0"/>
16             <port id="3" flag="0"/>
17             <port id="4" flag="0"/>
18             <port id="5" flag="0"/>
19             <port id="6" flag="0"/>
20         </card>
21         <card id="3">
22             <port id="1" flag="0"/>
23             <port id="2" flag="0"/>
24             <port id="3" flag="0"/>
25             <port id="4" flag="0"/>
26             <port id="5" flag="0"/>
27         </card>
28     </pin>
29     <pin id="2">
30         <card id="1">
31             <port id="1" flag="1"/>
32             <port id="2" flag="0"/>
33             <port id="3" flag="1"/>
34             <port id="4" flag="0"/>
35             <port id="5" flag="1"/>
36             <port id="6" flag="0"/>
37             <port id="7" flag="0"/>
38         </card>
39         <card id="2">
40             <port id="1" flag="0"/>
41             <port id="2" flag="0"/>
42             <port id="3" flag="0"/>
43             <port id="4" flag="0"/>
44             <port id="5" flag="0"/>
45             <port id="6" flag="0"/>
46         </card>
47     </pin>
48 </information>

pin2的card1中的一些端口flag状态已经改变

代码如下:
1 connect(ui->portlistWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(portSelected(QListWidgetItem*)));//点击端口
 1 void configure_win::portSelected(QListWidgetItem *item)
 2 {
 3     //qDebug()<<"&&&&&&&&&&&&&&&&&&&";
 4     g_port = item->text();
 5     if (item->checkState() == Qt::Checked)//添加
 6     {
 7         _linkUpdate(g_pin,g_card,g_port,1);//链路
 8         _xmlUpdate(g_pin,g_card,g_port,1);//XML文件
 9     }
10     else//删除
11     {
12         _linkUpdate(g_pin,g_card,g_port,0);;//链路
13         _xmlUpdate(g_pin,g_card,g_port,0);//XML文件
14     }
15 }
 1 /*
 2 *函数名:_xmlUpdate
 3 *功能:更新xml文件信息
 4 *
 5 */
 6 void configure_win::_xmlUpdate(QString pin, QString card, QString port, int number)
 7 {
 8     //qDebug()<<i;
 9     QDomDocument doc;
10     QDomAttr Flag = doc.createAttribute("flag");
11     QFile file("../project/ini/write.xml");
12     if (!file.open(QIODevice::ReadWrite))
13     {
14         return;
15     }
16     if (!doc.setContent(&file))
17     {
18         file.close();
19         return;
20     }
21     file.close();
22     
23     QString strNumberPin = pin.right(1);
24     QString strTypePin = pin.left(pin.length() - 1);//去掉最后一位
25     QString strNumberCard = card.right(1);
26     QString strTypeCard = card.left(card.length() - 1);//去掉最后一位
27     QString strNumberPort = port.right(1);
28     QString strTypePort = port.left(port.length() - 1);//去掉最后一位port
29     
30     QDomNodeList list = doc.elementsByTagName(strTypePin);//查找探针项
31     for (int i = 0;i < list.count();i++)
32     {
33         QDomElement e = list.at(i).toElement();
34         if (e.attribute("id") == strNumberPin)//找到对应的探针
35         {
36             //ui->cardlistWidget->clear();//清空板卡
37             QDomNodeList childCard = e.childNodes();
38             for (int j = 0;j < childCard.count();j++)//遍历板卡
39             {
40                 QDomElement card = childCard.at(j).toElement();              
41                 //qDebug()<<"      "<<qPrintable(card.tagName())<<qPrintable(card.attribute("id"));             
42                 if (card.attribute("id") == strNumberCard)
43                 {
44                     QDomNodeList childPort = card.childNodes();
45                     
46                     for (int k = 0;k < childPort.count();k++)
47                     {
48                         QDomNode port = childPort.at(k);
49                         
50                         if (port.toElement().attribute("id") == strNumberPort)
51                         {
52                             QString num = QString::number(number);
53                             //qDebug()<<num;
54                             port.toElement().setAttribute("flag",num); //把属性写入xml文件
55                             goto _NEXT;
56                         }
57                     }
58                 }
59             }
60         }
61     }   
62 _NEXT:
63     QFile f("../project/ini/write.xml");
64     //if(!f.open(QIODevice::WriteOnly|QIODevice::Truncate))
65     if(!f.open(QIODevice::WriteOnly|QIODevice::Truncate))
66     {
67         return;
68     }
69     QTextStream out(&f);
70     doc.save(out,4);
71     f.close();
72 }

 

好了,我的XML操作到这里都实现了,最后我根据需要,添加了移除按钮的信息,也对XML中的port属性进行修改

1 connect(ui->linkWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(mylinkWidgetSelect(QListWidgetItem*)));//移除,禁用按钮可用
 1 /*
 2 *槽函数名:on_removeBtn_clicked
 3 *功能:单击移除按钮,移除选中端口
 4 *
 5 */
 6 void configure_win::on_removeBtn_clicked()
 7 {
 8     QMessageBox msgBox;
 9     msgBox.setWindowTitle(tr("提示"));
10     msgBox.setText(tr("确定要删除端口?"));
11     msgBox.setIcon(QMessageBox::Information);
12     msgBox.addButton(tr("确定(&Y)"),QMessageBox::YesRole);
13     msgBox.addButton(tr("取消(&N)"),QMessageBox::NoRole);
14     msgBox.setStyleSheet("background-color:grey");
15     int ret = msgBox.exec();
16     if (ret == 0)//删除端口
17     {
18         int row = ui->linkWidget->currentRow();
19         QString strlink = ui->linkWidget->item(row)->text();
20         QStringList listlink = strlink.split("->");
21             QString pin = listlink.at(0);
22             QString card = listlink.at(1);
23             QString port = listlink.at(2);
24             _xmlUpdate(pin,card,port,0);//更新xml文件
25             if (pin == g_pin && card == g_card)
26             {
27                 for (int j =0;j < ui->portlistWidget->count();j++)
28                 {
29                     //qDebug()<<ui->portlistWidget->item(j)->text();
30                     if (ui->portlistWidget->item(j)->text() == port)
31                     {
32 
33                         ui->portlistWidget->item(j)->setCheckState(Qt::Unchecked);
34                         break;
35                     }
36                 }
37             }
38         ui->linkWidget->takeItem(row);
39     }
40 }

忘了加一句,需要在.pro文件中添加QT += xml  

这样才能使用XML的一些类

花了两天半的时间,终于把项目需要的一些对XML的操作搞定了