ifstream fin("tree.xml");
if (fin.fail()) return 1;
fin.seekg(0, ios::end);
size_t length = fin.tellg();
fin.seekg(0, ios::beg);
char* buffer = new char[length + 1];
fin.read(buffer, length);
buffer[length] = '\0';
fin.close();
xml_document<> doc;
doc.parse<parse_full>(buffer);
// doc.parse<0>(buffer);
delete [] buffer;
cout << "The first node is '" << doc.first_node()->name() << "'\n";
for (xml_node<>* n = doc.first_node("card")->first_node(); n;
n = n->next_sibling())
{
char* v = n->value();
if (!v || !*v) v = "(empty)";
cout << n->name() << " : " << v << '\n';
}
This is the code which i have written for XML parsing using RapidXML, but it throws exception "rapidxml::parse_error at memory location 0x0011fc20.." Please suggest any fix for this. Thanx
You may be able to nail down exactly what is causing this by looking at this link http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1parse__error
In particular (bold text is my emphasis)
class rapidxml::parse_error
Defined in rapidxml.hpp
Description
Parse error exception. This exception is thrown by the parser when an error
occurs. Use what() function to get human-readable error message. Use
where() function to get a pointer to position within source text where
error was detected.
this will at least let you discover what is causing the exception as well as the location. In addition your code does have an issue that could cause problems. This is taken from the rapidXML description of the parse function http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c
The bold text is emphasised by me
Parses zero-terminated XML string according to given flags. Passed
string will be modified by the parser, unless
rapidxml::parse_non_destructive flag is used. The string must persist
for the lifetime of the document. In case of error,
rapidxml::parse_error exception will be thrown.
But in your code
xml_document<> doc;
doc.parse<parse_full>(buffer);
// doc.parse<0>(buffer);
delete [] buffer;
cout << "The first node is '" << doc.first_node()->name() << "'\n";
you are deleting the char buffer containing your string and afterwards calling functions on the doc object. This is a violation of the above documentation. I am not sure if this is the exact cause of your exception, but certainly deleting that buffer is going to cause problems. I would suggest using a try/catch block to catch the parse_error exception and then use the where() and what() functions to pinpoint the error. Also try moving the delete statement to the end of your code after you have completely finished calling functions on the doc object as that could also be causing problems.
Your parsed DOM object doc is based on your buffer at the memory so dont delete your buffer or delete just before quit
Related
I have a program where I attempt to take a string value out of a vector and convert it into a float. The string is guaranteed to be a numerical value based on how I'm parsing the input data. When I attempt to run my program, I get the following error.
libc++abi.dylib: terminating with uncaught exception of type std::invalid_argument: stof: no conversion
Abort trap: 6
I traced where the issue was coming from, and it was where I was calling stof() to convert the obtained value from the vector into a float. The issue also persists when I call stoi() on the values as well. I used a typeid call to verify the value and dumped the type to the console.
type of there_list[2]: NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
val of there_list[2]: 10
I have absolutely no idea why this is the case, or what this even is for that matter, as my vector is clearly a vector of strings.
The code in question is the following:
string there(buffer);
vector<string> there_list = parse_word_list(there);
// Decide where to send the message next
// if the intended recipient (who the message is addressed to) is in range, send directly to recipient
cout << "type of there_list[2]: " << typeid(there_list[2]).name() << endl;
cout << "val of there_list[2]: " << there_list[2] << endl;
float dist_to_recipient = distance(sensor.getX(), sensor.getY(), stof(there_list[2]), stof(there_list[3]));
where buffer is a char[] that was used to read in input data from a server. My parse_word_list(there) call returns a string vector of the "words" contained in there delimited by spaces.
The function is basic, and looks like this
vector<string> parse_word_list(string phrase){
istringstream parse(phrase);
vector<string> word_list;
// Traverse through all words
do {
// Read a word
string word;
parse >> word;
// Append the read word to the word_list
word_list.push_back(word);
} while(parse); // While there is more to read
return word_list;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to add data into a text file. However, i see for some reason it produces garbage data. I also notice, it will input the correct data once, but then it follow with garbage data.
void TextFileLogger::log(std::string msg){
using namespace std;
//ofstream output_file("students.data", ios::binary);
std::ofstream logFile;
// creating, opening and writing/appending data to a file
char filename[] = "log.txt";
logFile.open(filename, ios::binary | ios::app |ios::out);
if (logFile.fail())
{
std::cout << "The " << filename << " file could not be created/opened!" << std::endl;
// 0-normal, non zero - some errors
}
else
{
if (!logFile.write((char*)&msg, sizeof(msg)))
{
cout << "Could not write file" << endl;
}
else
{
streamsize bytesWritten = logFile.tellp();
if (bytesWritten != sizeof(msg))
{
cout << "Could not write expected number of bytes" << endl;
}
else
{
logFile << msg << std::endl;
cout << "file written OK" << endl;
}
}
}
}
That one is fun!
(char*)&msg does not do what you expect: std::string is mainly a pointer to a dynamically-allocated buffer which contains the actual data. When you take the std::string's address and try to read what's inside, you get a view of its innards, not its data. Using a C++ static_cast here would have spared you the trouble by telling you that the conversion makes no sense. sizeof(msg) similarly returns the size of the std::string, not the length of its data.
So, your solution is: use msg.data() and msg.size(), it's exactly what they're designed for.
But... why would it (sometimes) output your string, and a bunch of garbage? Well, std::strings typically use SSO (Small String Optimization). The std::string actually contains a small buffer, to store short enough strings without dynamic allocation. When you inspect the whole std::string object, you see this buffer pass by.
You are writing the contents of the whole std::string object, with all the member variables that it contains internally.
You either want:
logFile << msg;
or if you really want to use write():
logFile.write( msg.c_str(), msg.length());
And, I wonder: Why do create/open the file in binary mode, when you write strings afterwards?
And finally, you write the data twice, the second time in your last else clause.
The problem is with this line:
if (!logFile.write((char*)&msg, sizeof(msg)))
It should be this:
if (!logFile.write(msg.c_str(), msg.length()))
Since you are passing a std::string into the function, you should take advantage of the functions it provides (c_str() and length()) instead of trying to cast it to a char* (this always gets messy, plus you are casting away the const, which is also typically bad).
This:
if (!logFile.write((char*)&msg, sizeof(msg)))
is wrong in so many ways. msg is not an array of char, it's a std::string - lying to the compiler by using a cast is always a bad thing to do. And the size of a string is not the size of the characters it contains. Why the heck are you not using the obvios:
logfile << msg << std::endl;
Replace sizeof(msg) with msg.size(), sizeof() is not doing what you think!
Also (char*)&msg does not do whatever you think, use msg.data() instead.
logFile.write((char*)&msg, sizeof(msg));
should be rewritten to:
logFile.write(msg.data(), msg.size());
or, even better, because ofstream overrides operator<< for std::string:
logfile << msg;
So currently I am working on an assignment, and for a section of it I need to be able to read a .txt file into a linked list of type char. I was already confused trying to do this, so I set out on a different path and decided to try to copy the text from the file into a char array, and then one by one copy the values in the array into the linked list.
So far I have my program compiling and running up to a certain point, before I receive the error Segmentation fault (core dumped).
The code for reading the file is as follow:
void readFile(list<char> &originList, string fileName){
ifstream fileInput;
fileInput.open(fileName.c_str());
int arraySize = fileInput.gcount();
char tempHold[arraySize];
if (!fileInput) {
cout << "Can't open file: " << fileName << "\n";
} else {
string contents((istreambuf_iterator<char>(fileInput)), istreambuf_iterator<char>());
strcpy (tempHold, contents.c_str());
for (int x = 0; x < fileInput.gcount(); x++) {
originList.push_back(tempHold[x]);
}
}
fileInput.close();
}
Also to add some context, using cout I determined that the code stops running, instead presenting the error, at the following point:
strcpy (tempHold, contents.data());
Also, I am not 100% on how exactly they work, only a loose idea to be honest. I mostly sourced the idea from this Stack Overflow question,
How to copy a .txt file to a char array in c++, but got confused somewhere a long the way.
Thanks in advance for any help you can provide.
istream::gcount returns the number of characters extracted by the last unformatted input operation performed on the object. Since you did not read anything from the file, you should get something wrong.Call, for example, istream.getline(); before calling gcount()
Like my comment to your question says, read each character from the file and add it to the list.
void readFile(list<char> &originList, string fileName) {
ifstream fileInput(fileName.c_str());
if (!fileInput) {
cout << "Can't open file: " << fileName << "\n";
}
char c;
while (fileInput.get(c)) {
originList.push_back(c);
}
}
Note: while (fileInput.get(c)) This reads the character and returns the stream. When a stream is used as a bool value it checks to see if the stream is valid. Valid means eof() and bad() are both false. - From a comment to the answer to the question linked below.
My answer was adapted from this other Stack Overflow question: Reading from text file until EOF repeats last line
I created a C++ application that reads in XML files with the RapidXML parser. At one XML file that was shaped exactly the same as another one that worked, the parser threw an error:
"expected <"
The last five characters before the error were from the closing tag of the root element, so the error happened at the end-of-file:
</UW>
What I suspect this error to be related to, is a whitespace skipping bug being an issue with RapidXML v1.12 (I am using v1.13). I used no parsing flags (doc.parse<0>(bfr);).
According to this site, the bug was believed to be caused by faulty implementation of the "parse_trim_whitespace" parse flag. A patch was provided on that site, but there also seemed to be a problem with that patch.
The following is the XML document that caused this error. What I also don't understand - besides the reason for the error - is why the error didn't happen parsing another file with content of the same fashion. My application also successfully parses several other files before that file.
<?xml version="1.0" encoding="UTF-8"?>
<UW>
<Bez>EV005</Bez>
<Herst>Trumpf</Herst>
<Gesw>16</Gesw>
<Rad>1.6</Rad>
<Hoehe>100</Hoehe>
<Wkl>30</Wkl>
<BgVerf>Freibiegen</BgVerf>
<MaxBel>50</MaxBel>
<Kontur>0</Kontur>
<Grafik>0</Grafik>
</UW>
Part of my application were the error occours (this is the inside of a loop):
// Get "Bezeichnung" attribute
attr = subnode->first_attribute("Bezeichnung");
if ( !attr ){ err(ERR_FILE_INVALID,"Werkzeuge.xml"); return 0; }
name = attr->value();
// Get file name/URL
string fileName = name;
fileName.append(".xml");
// Open file
ifstream werkzeugFile(concatURL(PFAD_WERKZEUGE,fileName));
if(!werkzeugFile.is_open()) { err(ERR_FILE_NOTFOUND,fileName); return 0; }
// Get length
werkzeugFile.seekg(0,werkzeugFile.end);
int len = werkzeugFile.tellg();
werkzeugFile.seekg(0,werkzeugFile.beg);
// Allocate buffer
char * bfr = new char [len+1];
werkzeugFile.read(bfr,len);
werkzeugFile.close();
// Parse
SetWindowText(hwndProgress,"Parsing data: Werkzeuge/*.xml");
btmDoc.parse<0>(bfr);
// Get type of tool & check validity
xml_node<> *rt_node = btmDoc.first_node();
if ( strcmp(rt_node->name(),"OW") == 0 ){
isOW = true;
}
else if ( strcmp(rt_node->name(),"UW") == 0 ){
isUW = true;
}
else { err(ERR_FILE_INVALID,fileName); return 0; }
// Prepare for next loop iteration
delete[] bfr;
btmDoc.clear();
subnode = subnode->next_sibling();
Ah, I think I see it. Two things:
First, the ifstream is suspicious -- shouldn't it be opened in binary mode if you're jumping around in it using byte offsets (and somebody else is doing the parsing)? Passstd::ios::in | std::ios::binary as the second argument to the ifstream constructor.
Second, your memory management seems fine, except that you allocate one byte extra (the +1) but never seem to make use of it. I'm assuming you're missing bfr[len] = '\0'; after the contents are read in -- this explains the odd parse error at the end of the file, since the XML parser doesn't know it reached the end of the file -- it's parsing a null terminated string that isn't null terminated, and tries to parse random bytes of memory ;-)
I have a very annoying problem and I'm trying to solve it for lots of hours.
I'm using rapidXML with C++ to parse an XML file:
xml_document<> xmlin;
stringstream input; //initialized somewhere else
xmlin.clear();
xmlin.parse<0>(&(input.str()[0]));
cout << "input:" << input.str() << endl << endl;
xml_node<char> *firstnode = xmlin.first_node();
string s_type = firstnode->first_attribute("type")->value();
cout << "type: " << s_type << endl;
However I got this on the stdout:
input:<?xml version="1.0" encoding="utf-8"?><testxml command="testfunction" type="exclusive" />
type: exclusive" />
What could be the reason of this (printing the s_type variable)?
It's very annoying since I can't process the xml well.
Actually I found the solution.
Stringstream doesn't like when its content is getting modified (rapidXML does a fast in-situ parsing which means it modificates the contents of the array it gets).
However in the docs I read that string class does not like it either.
From the string::c_str documentation page:
the values in this array should not be modified in the program
But when I create a string from the stream it is working as it is expected:
xml_document<> xmlin;
stringstream input; //initialized somewhere else
string buffer = input.str()
xmlin.clear();
xmlin.parse<0>(&(buffer[0]));
I think the problem is in the code you haven't shown... Start by trying this, using a literal string - this works just fine for me...
xml_document<> xmlin;
char *input = "<?xml version=\"1.0\" encoding=\"utf-8\"?><testxml command=\"testfunction\" type=\"exclusive\" />";
xmlin.parse<0>(input);
xml_node<char> *firstnode = xmlin.first_node();
std::string s_type = firstnode->first_attribute("type")->value();
I would personally recommend this approach
xml_document<> doc;
string string_to_parse;
char* buffer = new char[str_to_parse.size() + 1];
strcpy (buffer, str_to_parse.c_str());
doc.parse<0>(buffer);
delete [] cstr;
making a non const char array out of the string you want to parse. I have always found this way safer and more reliable.
I used to do such crazy things as
string string_to_parse;
doc.parse<0>(const_cast<char*>(string_to_parse.c_str()));
and it "worked" for a long time (until the day it didn't when I needed to reuse the original string). Since RapidXML can modify the char array it is parsing and since it is not recommended to change str::string via c_str() I have always used the approach of copying my string to a non const char array and pass that to the parser. It may not be optimal and uses additional memory, but it is reliable and I have never had any errors or problems with it to date. Your data will be parsed and the original string can be reused without fear of it having been modified.