I have been using the excellent rapidxml library to read and use information from XML files to hold cutscene information for a game I am programming in C++. I have run into an odd problem,
I start by loading the XML file into a rapidxml::xmldocument<>* from std::ifstream* XMLFile
std::stringstream buffer; //Create a string buffer to hold the loaded information
buffer << XMLFile->rdbuf(); //Pass the ifstream buffer to the string buffer
XMLFile->close(); //close the ifstream
std::string content(buffer.str()); //get the buffer as a string
buffer.clear();
cutScene = new rapidxml::xml_document<>;
cutScene->parse<0>(&content[0]);
root = cutScene->first_node();
my cutscene xml file is made up of "parts" and at the beginning I want to load all of those parts (which are all xml_nodes) into a vector
//Load parts
if (parts->size() == 0) {
rapidxml::xml_node<>* partNode = root->first_node("part");
parts->push_back(partNode);
for (int i = 1; i < numParts; i++) {
parts->push_back(partNode->next_sibling());
printf("name of part added at %i: %s.\n", i, parts->at(i)->name());
}
}
That last line prints "name of part added at 1: part" to the console. The problem is for some reason, whenever I try to access the vector and print the same name of that same specific part not as a part of this method, the name can be accessed but is just a random string of letters and numbers. It seems that for some reason rapidxml is deleting everything after my load method is complete. I am still new to posting on stackoverflow so if you need more information just ask, thanks!
Rapidxml is in-situ xml parser. It alters the original string buffer (content
in your case) to format null-terminated tokens such as element and attribute names. Secondly, the lifespan of tree nodes referenced byparts
items is defined by xml_document (currscene
) instance.
Keep currscene
and content
instances together with the vector, this will keep the vector items alive as well.
e.g:
struct SceneData
{
std::vector<char> content;
rapidxml::xml_document<> cutScene;
std::vector<rapidxml::xml_node<>*> parts;
bool Parse(const std::string& text);
};
bool SendData::Parse(const std::string& text)
{
content.reserve(text.length() + 1);
content.assign(text.begin(), text.end());
content.push_back('\0');
parts.clear();
try
{
cutScene.parse<0>(content.data());
}
catch(rapidxml::parse_error & err)
{
return false;
}
// Load parts.
rapidxml::xml_node<>* root = cutScene.first_node();
rapidxml::xml_node<>* partNode = root->first_node("part");
parts->push_back(partNode);
for (int i = 1; i < numParts; i++) {
parts->push_back(partNode->next_sibling());
//printf("name of part added at %i: %s.\n", i, parts->at(i)->name());
}
return true ;
}
EDITED
The parser expects a sequence of characters terminated by '\0 as input. Since a buffer referenced by &string[0] is not guaranteed to be null-terminated, it is recommended to copy the string content into std::vector<char>
.