Read and Write to an XML file using C++ and TinyXML2

C++ is one of the most powerful programming languages, making its presence felt in every corner of the development world. Since its inception in 1985, C++ has been the go-to language for learners, engineers, scientists, and researchers alike.

Picture this: You have an application written in C++ that needs to save and access data from an XML file. What do you do? Well, you’ve got a couple of choices. You could become your own XML parsing mastermind, which is quite a challenge if you have the time and skillset. Alternatively, you could take a shortcut and employ an XML parser like TinyXML2, diving into its inner workings without a sweat.

In this tutorial, you will learn how to Read and Write to an XML file using C++ and TinyXML2, an XML parser developed by Lee Thomason.


TinyXML2 and C++ Tutorial

First, download the TinyXML library by clicking on the following link:

https://github.com/leethomason/tinyxml2

Afterward, it is necessary to incorporate the library into your project, which varies based on your IDE. Detailed instructions for this process can be found by visiting the link below:

https://github.com/leethomason/tinyxml2/blob/master/readme.md

Create an XML File

For the sake of this tutorial, let’s create an XML file for employees’ records. Below is the structure of the file that we will be using in this tutorial:

<data>
    <Employees>
        <Employee>
            <Name>Mike</Name>
            <Department>Engineering</Department>
            <Positing>Engineer</Positing>
            <Salary>5000</Salary>
            <HireData>01/01/2021</HireData>
        </Employee>
 
        <Employee>
            <Name>Fred</Name>
            <Department>Human Resource</Department>
            <Positing>Administration Assistant</Positing>
            <Salary>3000</Salary>
            <HireData>01/01/2016</HireData>
        </Employee>
        
        <Employee>
            <Name>Nancy</Name>
            <Department>Information Technology</Department>
            <Positing>Programmer</Positing>
            <Salary>4000</Salary>
            <HireData>01/01/2014</HireData>
        </Employee>
    </Employees>
</data>

The file above contains information about employees. It features details about three staff members, each enclosed within a <Employee> tag, and the entire collection of employees is enclosed within a <Employees> (with s) tag.

How to Read from an XML file using TinyXML2

The first operation in this tutorial is reading an XML file. The code below reads the data from the XML file, formats it, then prints it to the console.

#include <iostream>
#include <tinyxml2.h>
#include <iomanip>

using namespace std;
using namespace tinyxml2;

int main() {
  XMLDocument doc;
  const char * path = "\\bin\\Debug\\data.xml";
  char salaryText[20];

  // Load XML data
  doc.LoadFile(path);

  // Get the root Element from the XMLDocument instance
  XMLElement * pRootElement = doc.RootElement();

  // Print the Header
  cout << '|' << setw(6) << "Name" << '|' << setw(14) << "Department" << '|' << setw(12) << "Position" << '|' << setw(8) << "Salary" << '|' << setw(12) << "Hire Date" <<
    endl;
  cout << "----------------------------------------------------------";
  cout << endl;
  if (pRootElement != NULL) {

    //Get 'Employees' Node
    XMLElement * pEmployees = pRootElement -> FirstChildElement("Employees");
    if (NULL != pEmployees) {

      //Get 'Account' Node
      XMLElement * pEmployee = pEmployees -> FirstChildElement("Employee");
      while (pEmployee) {

        // Get 'Name' Node
        XMLElement * pName = pEmployee -> FirstChildElement("Name");
        if (pName != NULL) {

          //Print 'Name'
          cout << '|' << setw(6) << pName -> GetText();
        }

        //Get 'Department' Node
        XMLElement * pDepartment = pEmployee -> FirstChildElement("Department");
        if (pDepartment != NULL) {

          // Print 'Department'
          cout << '|' << setw(14) << pDepartment -> GetText();
        }

        // Get 'Position' Node
        XMLElement * pPosition = pEmployee -> FirstChildElement("Position");
        if (pPosition != NULL) {

          //Print 'Position'
          cout << '|' << setw(12) << pPosition -> GetText();
        }

        // Get 'Salary' Node
        XMLElement * pSalary = pEmployee -> FirstChildElement("Salary");
        if (pSalary != NULL) {

          // Convert the double value to *char
          strcpy(salaryText, "$");
          strcat(salaryText, pSalary -> GetText());

          //Print 'Salary'
          cout << '|' << setw(8) << salaryText << '|';
        }

        XMLElement * openDate = pEmployee -> FirstChildElement(strdup("HireData"));
        if (openDate != NULL) {

          //Print the openDate Node
          cout << setw(12) << openDate -> GetText() << '|';
        }
        cout << endl;

        // Next Employee
        pEmployee = pEmployee -> NextSiblingElement("Employee");
      }
      cout << "\n";
    }
  }
  return 0;
}

Run your program, you should get the following output:

|  Name|    Department|    Position|  Salary|   Hire Date
----------------------------------------------------------
|  Mike|   Engineering|    Engineer|   $5000|  01/01/2021|
|  Fred|            HR|   Assistant|   $3000|  01/01/2016|
| Nancy|            IT|  Programmer|   $4000|  01/01/2014|


Process returned 0 (0x0)   execution time : 1.118 s
Press any key to continue.

Insert a new row to an XML file using TinyXML2

Are you ready to bring a fresh new employee on board? Great! Let’s utilize the insert operation by implementing the InsertEndChild function from the TinyXML2 library:

void InsertEmployee() {

  XMLDocument doc;
  const char * path = "\\bin\\Debug\\data.xml";

  // Define new employee Data
  char name[100] = "Mark";
  char department[100] = "IT";
  char position[20] = "QA";
  char salary[10] = "3000";
  char hireDate[20] = "05/12/2023";

  // Load XML data
  doc.LoadFile(path);

  //Get root Element
  XMLElement * root = doc.RootElement();

  // Get 'Employees' Child
  XMLElement * Employees = root -> FirstChildElement("Employees");

  //Create new Employee
  XMLNode * pRoot = doc.NewElement("Employee");

  //Insert new Element
  Employees -> InsertEndChild(root);

  //Create 'Name' Element
  XMLElement * pElement = doc.NewElement("Name");

  // Set new Element Value
  pElement -> SetText(name);

  // Insert new Element
  pRoot -> InsertEndChild(pElement);

  //Create 'Department' Element
  pElement = doc.NewElement("Department");

  // Set new Element Value
  pElement -> SetText(department);

  // Insert new Element
  pRoot -> InsertEndChild(pElement);

  //Create 'Position' Element
  pElement = doc.NewElement("Position");

  // Set new Element Value
  pElement -> SetText(position);

  // Insert new Element
  pRoot -> InsertEndChild(pElement);

  //Create 'Salary' Element
  pElement = doc.NewElement("Salary");

  // Set new Element Value
  pElement -> SetText(salary);

  // Insert new Element
  pRoot -> InsertEndChild(pElement);

  //Create 'HireDate' Element
  pElement = doc.NewElement("HireDate");

  // Set new Element Value
  pElement -> SetText(hireDate);

  //Insert new Element
  pRoot -> InsertEndChild(pElement);

  //Apply the changes to the XML file
  doc.SaveFile(path);
}

Run the function, the output for the new XML data file is as the following:

|  Name|    Department|    Position|  Salary|   Hire Date
----------------------------------------------------------
|  Mike|   Engineering|    Engineer|   $5000|  01/01/2021|
|  Fred|            HR|   Assistant|   $3000|  01/01/2016|
| Nancy|            IT|  Programmer|   $4000|  01/01/2014|
|  Mark|            IT|          QA|   $3000|  05/12/2023|


Process returned 0 (0x0)   execution time : 0.557 s
Press any key to continue.

of course, you have the option to modify this function by incorporating parameters, enabling you to call it and pass your specific parameters.

Happy Coding!