最近要做一个VRP的算法,测试集都是放在Xml文件中,而我的算法使用C++来写,所以需要用C++来读取Xml文件。
在百度上搜“C++读取Xml文件”,可以出来很多博客,大多数是关于tinyXml的,所以这篇博文也是讲述如何用tinyXML来读取XML文件。
有些内容可能参考到了@marchtea的博文《C++读取XML,tinyXml的使用》:http://www.cnblogs.com/marchtea/archive/2012/11/08/2760593.html。
tinyXml是一个免费开源的C++库,可以到官网上下载:https://sourceforge.net/projects/tinyxml/。
下载下来解压之后,可以看到下面这些文件:
我是在windows下用VS来写C++的,按照@marchtea的说法,只需要直接打开tinyxml.sln就可以,不过我还是用了笨办法:
把tinystr.cpp,tinyxml.cpp,tinyxmlerror.cpp,tinyxmlparser.cpp,tinystr.h,tinyxml.h拷贝到工程目录下;
然后加入头文件引用:#include"tinystr.h"#include"tinyxml.h"。
接下来就来分享一下我读取VRP问题中的solomonbenchmark的方法,这些方法都是参考自tinyXml的官方教程,在下载的文件夹中有"doc"子文件夹,打开它,有一个叫做"tutorial0"的html文件,打开它可以看到详细的教程。
OK,nowbegins!
我要读取的Xml文件有如下的格式(只列举部分):
<!--要读取的Xml文件--> <?xmlversion="1.0"encoding="UTF-8"standalone="yes"?> <instance> <network> <nodes> <nodeid="0"type="0"> <cx>40.0</cx> <cy>50.0</cy> </node> <!--有N+1个这样的node节点--> </nodes> </network> <requests> <requestid="1"node="1"> <tw> <start>145</start> <end>175</end> </tw> <quantity>20.0</quantity> <service_time>10.0</service_time> </request> <!--有N个这样的request节点--> </requests> </instance> |
这里稍微解释一下为什么nodes节点的数目会比requests节点多1个。这是因为nodes节点包括了顾客节点(N个)和仓库节点(1个),而requests属性只属于顾客节点。
我是把xml文件中的这些数据读入到类对象数组中,每个类对象代表一个节点,类的定义如下:
//Customer.h #ifndef_Customer_H #define_Customer_H classCustomer{ public: Customer(intid=0,floatx=0,floaty=0,floatstartTime=0,floatendTime=0,floatquantity=0,floatserviceTime=0); voidsetId(intid);//设置成员id的值 voidsetX(floatx);//设置成员x的值 voidsetY(floaty);//设置成员y的值 voidsetStartTime(floatstartTime);//设置成员startTime的值 voidsetEndTime(floatendTime);//设置成员endTime的值 voidsetQuantity(floatquantity);//设置成员quantity的值 voidsetServiceTime(floatserviceTime);//设置成员serviceTime的值 voidshow();//显示顾客节点信息 private: intid; floatx; floaty; floatstartTime; floatendTime; floatquantity; floatserviceTime; }; #endif |
OK,那么现在开始贴一下main.cpp代码(Customer.cpp比较简单,就不贴了)
//main.cpp #include"Customer.h" #include"tinystr.h" #include"tinyxml.h" #include<iostream> #include<vector> #include<string> #include<stdlib.h> #include<iomanip> usingnamespacestd; staticconstintNUM_OF_CUSTOMER=51;//顾客数量 staticconstchar*FILENAME="RC101_050.xml";//文件名 intmain(){ vector<Customer*>customerSet(0);//顾客集,每个元素是Customer对象的指针 inti,j,k,count; inttemp1;//存放整型数据 floattemp2;//存放浮点型数据 Customer*customer;//临时顾客节点指针 for(i=0;i<NUM_OF_CUSTOMER;i++){//先初始化顾客集 customer=newCustomer(); customerSet.push_back(customer); } TiXmlDocumentdoc(FILENAME);//读入XML文件 if(!doc.LoadFile())return-1;//如果无法读取文件,则返回 TiXmlHandlehDoc(&doc);//hDoc是&doc指向的对象 TiXmlElement*pElem;//指向元素的指针 pElem=hDoc.FirstChildElement().Element();//指向根节点 TiXmlHandlehRoot(pElem);//hRoot是根节点 //读取x,y,它们放在network->nodes->node节点中 TiXmlElement*nodeElem=hRoot.FirstChild("network").FirstChild("nodes").FirstChild("node").Element();//当前指向了node节点 count=0;//记录移动到了哪个node节点,并且把该node节点的信息录入到顺序对应的customer中 for(nodeElem;nodeElem;nodeElem=nodeElem->NextSiblingElement()){//挨个读取node节点的信息 customer=customerSet[count];//当前顾客节点,注意不能赋值给一个新的对象,否则会调用复制构造函数 TiXmlHandlenode(nodeElem);//nodeElem所指向的节点 TiXmlElement*xElem=node.FirstChild("cx").Element();//cx节点 TiXmlElement*yElem=node.FirstChild("cy").Element();//cy节点 nodeElem->QueryIntAttribute("id",&temp1);//把id放到temp1中,属性值读法 customer->setId(temp1); temp2=atof(xElem->GetText());//char转float customer->setX(temp2); temp2=atof(yElem->GetText()); customer->setY(temp2); count++; } //读取其余信息 TiXmlElement*requestElem=hRoot.FirstChild("requests").FirstChild("request").Element();//指向了request节点 count=1; for(requestElem;requestElem;requestElem=requestElem->NextSiblingElement()){ customer=customerSet[count];//当前顾客节点,注意不能赋值给一个新的对象,否则会调用复制构造函数 TiXmlHandlerequest(requestElem);//指针指向的对象 TiXmlElement*startTimeElem=request.FirstChild("tw").FirstChild("start").Element();//starttime TiXmlElement*endTimeElem=request.FirstChild("tw").FirstChild("end").Element();//endtime TiXmlElement*quantityElem=request.FirstChild("quantity").Element();//quantity TiXmlElement*serviceTimeElem=request.FirstChild("service_time").Element();//servicetime //分别读取各项数据 temp2=atof(startTimeElem->GetText()); customer->setStartTime(temp2); temp2=atof(endTimeElem->GetText()); customer->setEndTime(temp2); temp2=atof(quantityElem->GetText()); customer->setQuantity(temp2); temp2=atof(serviceTimeElem->GetText()); customer->setServiceTime(temp2); count++; } //将读取到的信息输出到控制台 cout<<setiosflags(ios_base::left)<<setw(6)<<"id"<<setw(6)<<"x"<<setw(6)<< "y"<<setw(12)<<"startTime"<<setw(12)<<"endTime"<<setw(12)<<"quantity"<<setw(14)<<"serviceTime"<<endl; for(i=0;i<NUM_OF_CUSTOMER;i++){ customer=customerSet[i]; customer->show(); } system("pause"); return0; } |