c++rapidxml

Can't correctly open the next XML file in a loop while using RapidXML


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.


Solution

  • 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());