Recently to do a VRP algorithm, the test set is placed in an XML file, and my algorithm is written in C + +, so I need to use C + + to read the XML file.
On Baidu Search "C + + read XML file", can come out a lot of blogs, mostly about tinyxml, so this blog is also about how to use TinyXML to read XML files.
Some of the content may refer to @marchtea's blog, "C + + read Xml,tinyxml use": http://www.cnblogs.com/marchtea/archive/2012/11/08/2760593.html.
TinyXML is a free open source C + + library that can be downloaded to the official website: https://sourceforge.net/projects/tinyxml/.
After downloading the extract, you can see the following files:
I use vs to write C + + in Windows, according to @marchtea, only need to open tinyxml.sln directly, but I still use a stupid way:
- Copy tinystr.cpp, Tinyxml.cpp, Tinyxmlerror.cpp, Tinyxmlparser.cpp, Tinystr.h, tinyxml.h to the project directory;
- Then add the header file reference: #include "tinystr.h" #include "tinyxml.h".
Next, let's share some of the ways I read the Solomon benchmark in the VRP problem, all of which refer to the official tutorial from TinyXML, the "Doc" subfolder in the downloaded folder, open it, and a HTML file called "Tutorial0". Open it to see a detailed tutorial.
Ok,now begins!
The XML file I want to read has the following format (just a few examples):
<!--the XML file to read--><?xml version= "1.0" encoding= "UTF-8" standalone= "yes"?><instance> < network> <nodes> <node id= "0" type= "0" > <cx>40.0</cx> <cy>50.0 </cy> </node> <!-- have n+1 nodes-- </nodes> </network> <requests> <request id= "1" node= "1" > <tw> <start>145</start> <end>175</end> </tw> <quantity>20.0</quantity> <service_ time>10.0</service_time> </request> <!--have n such a request node-- </requests ></instance>
Here's a little explanation of why the number of nodes nodes is one more than the requests node. This is because the nodes node consists of a customer node (n) and a warehouse node (1), while the requests attribute belongs to the customer node only.
I read this data from an XML file into an array of class objects, each of which represents a node, and the class is defined as follows:
Customer.h#ifndef _customer_h#define _customer_hclass customer{public:customer (int id=0, float x=0, float y=0, float s Tarttime=0, float endtime=0, float quantity=0, float servicetime=0); void setId (int id); Sets the value of member ID void SetX (float x); Sets the value of member x void sety (float y); Sets the value of member Y for void Setstarttime (float startTime); Sets the value of member StartTime void Setendtime (float endTime); Sets the value of member Endtime void setquantity (float quantity); Sets the value of member quantity void Setservicetime (float serviceTime); Sets the value of member Servicetime void Show (); Display Customer node information private:int id;float x;float y;float starttime;float endtime;float quantity;float serviceTime;}; #endif
OK, so now start to paste the Main.cpp code (Customer.cpp is relatively simple, it is not affixed)
Main.cpp#include "Customer.h" #include "tinystr.h" #include "tinyxml.h" #include <iostream> #include <vector > #include <string> #include <stdlib.h> #include <iomanip>using namespace std;static const int NUM_ Of_customer = 51; Number of customers static const char* FILENAME = "Rc101_050.xml"; File name int main () {Vector<customer *> customerset (0); The customer set, each element is a pointer to the customer object int I,j,k,count;int Temp1; Storing integer data float temp2; Storing floating-point data customer* customer; Temporary customer node pointer for (i=0; i<num_of_customer; i++) {//Initialize customer set First client = new customer (); Customerset.push_back (customer); Tixmldocument doc (FILENAME); Read in the XML file if (!doc. LoadFile ()) return-1; If the file cannot be read, Tixmlhandle Hdoc (&doc) is returned; Hdoc is the object that the &doc points to tixmlelement* Pelem; Pointer to Element Pelem = Hdoc.firstchildelement (). Element (); Point to root node Tixmlhandle hroot (Pelem); Hroot are root nodes//read x, y, and they are placed in the Network->nodes->node node tixmlelement* nodeelem = hroot.firstchild ("Network"). FirstChild ("Nodes"). FirstchILD ("Node"). Element (); Node is currently pointing to Count = 0; Records the node that was moved to, and input the node information into the order corresponding to the customer for (Nodeelem; nodeelem; nodeelem = Nodeelem->nextsiblingelement ( ) {//Read the node's information to Customer = Customerset[count]; The current customer node, note that you cannot assign a value to a new object, or you call the copy constructor Tixmlhandle node (Nodeelem); The node that Nodeelem points to tixmlelement* Xelem = nodes. FirstChild ("CX"). Element (); CX node tixmlelement* yelem = node. FirstChild ("Cy"). Element (); CY Node Nodeelem->queryintattribute ("id", &TEMP1); Put the ID into the Temp1, the attribute value reading method Customer->setid (TEMP1); Temp2 = Atof (Xelem->gettext ()); Char to Floatcustomer->setx (TEMP2); temp2 = Atof (Yelem->gettext ()); Customer->sety (TEMP2); count++;} Read the rest of the information tixmlelement* Requestelem = Hroot.firstchild ("Requests"). FirstChild ("Request"). Element (); Point to request node count = 1;for (Requestelem; requestelem; requestelem = Requestelem->nextsiblingelement ()) {customer = Customerset[count]; The current customer node, note that you cannot assign a value to a new object, or the copy constructor Tixmlhandle request (Requestelem) is called; The object pointed to by the pointer Tixmlelement* Starttimeelem = Request. FirstChild ("TW"). FirstChild ("Start"). Element (); Start timetixmlelement* Endtimeelem = Request. FirstChild ("TW"). FirstChild ("End"). Element (); End timetixmlelement* Quantityelem = Request. FirstChild ("Quantity"). Element (); quantitytixmlelement* Servicetimeelem = Request. FirstChild ("Service_time"). Element (); Service time//read each data 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++;} Output the Read information to the console Cout<<setiosflags (ios_base::left) <<SETW (6) << "id" <<SETW (6) << "X" <<SETW (6) << "Y" <<setw (12) << "StartTime" <<SETW (a) << "EndTime" <<SETW << "Quantity" <<SETW << "ServiceTime" <<endl;for(i=0; i<num_of_customer; i++) {customer = Customerset[i];customer->show ();} System ("pause"); return 0;}
Before explaining the contents of main.cpp, explain some data types (just personal understanding, welcome to Error correction):
- Tixmldocument: A file node that reads the contents of an XML file into a variable of that type
- tixmlelement*: Pointer to Node
- Tixmlhandle: an instance of a node, which is the object that tixmlelement points to
- FirstChild ("NodeName"): The first child node named "NodeName"
- Nextsiblingelement (): Next sibling node element, they have the same parent node
- Queryintattribute ("AttributeName", &var): Assigns the attribute value of the node property named AttributeName to the VAR variable with the int type
- GetText (): Gets the contents of the current node element, which is the text contained in <node>text</node>
OK, with some of the above simple knowledge accumulation, it is easy to read the XML file, now intercept the XML part to explain:
<instance> <network> <nodes> <node id= "0" type= "0" > <cx>40.0</ cx> <cy>50.0</cy> </node> <!-- have n+1 nodes like this--- </nodes> </network> .....</instance>
In this section we will read the customer ID, coordinates x, Y, into the customer object.
1. First we get the file node Hdoc, now we want to enter the root node "instance":
tixmlelement* Pelem; Pointer to Element Pelem = Hdoc.firstchildelement (). Element (); Point to root node Tixmlhandle hroot (Pelem); Hroot is the root node
The root node "instance" is the first child node of a file node, so use Pelem = Hdoc.firstchildelement (). Element () causes the pointer pelem to point to "instance", Hroot is the object that the Pelem points to.
2. Now we need to go into the nodes node, traverse its sibling node, and read all the data into it. The following statement assigns a pointer to the Nodeelem for the first "node" nodes:
tixmlelement* Nodeelem = hroot.firstchild ("Network"). FirstChild ("Nodes"). FirstChild ("Node"). Element (); Node is currently pointed to
The ID value of the node is placed in the attribute "id" of the "node":
Nodeelem->queryintattribute ("id", &TEMP1); Put the ID into the Temp1, the attribute value reading method
Then the value of coordinates x, Y is placed in the contents of "CX" and "Cy" of the child node of "node", so we read:
tixmlelement* Xelem = node. FirstChild ("CX"). Element (); CX node Temp2 = atof (Xelem->gettext ()); Char to float
The function atof in library <stdlib> to convert a char array into a floating-point number.
With 1, 22 steps, we have read the first node's ID, x, y values into the object, and then simply traverse through all the sibling nodes:
for (Nodeelem; nodeelem; nodeelem = Nodeelem->nextsiblingelement ()) {...}
Read into the Requests node StartTime, EndTime, quantity, Servicetime equivalent method is the same, the details refer to the Main.cpp code.
The results of the operation are as follows:
Summarize:
In fact, the key to reading the XML file is:
- Move the pointer to the node where you want to read the data;
- If the value of the property is read, it is read directly using the Queryintattribute method;
- If the content of the node is read, it is read using the GetText () method;
- Continuous data has sibling node relationships, using the Nextsiblingelement () method to point to the next sibling node
Postscript:
This blog post only describes how to read XML files, as for how to write XML files, please refer to TinyXML's official tutorial, especially clear, special conscience.
Hope that we have seen after the harvest, welcome to Exchange.
C + + read into XML file