首页 > 代码库 > 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的操作搞定了