I am trying to make a program that opens a list of XML files and recovers some data from them so I decided to use RapidXML.
Everything is fine for the first document but after I try to open another file in a loop the program crashes because RapidXML function finds a null pointer to the next child.
I have tried placing the RapidXML declarations in a global scope so that they don't get destroyed but the problem still persists. What can I do?
Here's the code:
#include <filesystem>
#include <string>
#include <fstream>
#include <streambuf>
#include <sys/stat.h>
#include "rapidxml.hpp"
#include <iostream>
using namespace rapidxml;
using namespace std;
namespace fs = std::filesystem;
xml_document<> doc;
xml_node<>* node;
xml_node<>* child;
int main()
{
int counter = 0;
std::string path;
struct stat sb;
// Fase di ricezione del percorso dei file da leggere in XML
cout << "Inserire il percorso dove sono presenti i file da leggere:\n";
do {
if (counter > 0) cout << "Attenzione, percorso non valido!\n";
cin >> path;
counter++;
} while (stat(path.c_str(), &sb));
cout << "Percorso valido.\n";
// Fase di lettura della lista dei file presenti nella cartella sopra selezionata
for (const auto& entry : fs::directory_iterator(path))
{
if (entry.path().extension().string().ends_with(".xml"))
{
if (entry.path().string().ends_with(".xml_metaDato.xml")) continue;
// Fase di apertura e impostazione del percorso
else {
cout << entry.path() << std::endl;
std::ifstream t(entry.path().filename());
std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
str.append("\0");
doc.parse<0>(&str[0]); // 0 means default parse flags
// if (doc.first_node() == nullptr) cout << "Trying to reference a null pointer";
// cout << doc.first_node()->name() << "\n";
node = doc.first_node();
for (child = node->first_node(); child; child = child->next_sibling())
{
cout << child->name() << std::endl;
}
doc.clear();
t.close();
}
}
}
}
The problem is here, at the last part of the most inner if:
node = doc.first_node();
for (child = node->first_node(); child; child = child->next_sibling())
{
cout << child->name() << std::endl;
}
After opening a new file it tries to read data from it but it crashes for a null pointer.
The error has nothing to to do with rapidxml. The line of code
std::ifstream t(entry.path().filename());
is incorrect since filename()
only returns the file name portion of the complete path, so given "C:/fred/john.xml"
it would return "john.xml"
. This means any file outside of the current working directory will fail to open.
The correct code is simply
std::ifstream t(entry.path());
although on older versions of C++ you might need
std::ifstream t(entry.path().c_str());