After reading text entry with QXmlStreamReader getting an entry with no visible characters when there should not be any.
Hi All;
I’m seeing some weird behavior with the QXmlStreamReader. After i read a text entry i keep getting an entry that has no visible characters. I’m creating a small app that will allow a person to create a config file in the following format:
- <?xml version="1.0" encoding="UTF-8"?>
- <DailyCheck>
- <USER ID="user1">
- <DateOfLastUpdate>Fri Jan 14 16:04:11 2011</DateOfLastUpdate>
- <QUESTIONS>
- <QUESTION ID="0">some question</QUESTION>
- </QUESTIONS>
- </USER>
- </DailyCheck>
it’s being written using QXmlStreamWriter which works flawlessly. Here is the code that i use to read the file:
- void DCPConfigController::ReadConfigFile()
- {
- mUserQuestions->clear();
- {
- //add code to log problem.
- return;
- }
- User* tUser = 0;
- while (!tReader.atEnd())
- {
- {
- if (tReader.name() == USER_TAG)
- {
- tUser = ParseUser(tReader, tUserName);
- mUserQuestions->insert(tUserName, *tUser);
- }
- }
- }
- tFile.close();
- }
- {
- aReader.readNext();
- User* tUser = new User();
- tUser->UserName(aUserName);
- {
- if(aReader.name() == LAST_UPDATE_TAG && !aReader.isWhitespace())
- {
- tUser->LastUpdate(GetDataString(aReader));
- }
- if (aReader.name() == QUESTION_AREA_TAG && !aReader.isWhitespace())
- {
- tUser->Questions(ParseQuestions(aReader));
- }
- aReader.readNext();
- }
- return tUser;
- }
- {
- aReader.readNext();
- QStringList tQuestions;
- while(!(aReader.tokenType() == QXmlStreamReader::EndElement && aReader.name() == QUESTION_AREA_TAG))
- {
- if (aReader.name() == QUESTION_TAG && !aReader.isWhitespace())
- {
- tQuestions.append(GetDataString(aReader));
- }
- aReader.readNext();
- }
- return tQuestions;
- }
- {
- {
- }
- aReader.readNext();
- return aReader.text().toString();
- }
However as i read the file and i read the text entry for the “DateOfLastUpdate” which is done in the parse user method, it will read the text and store it properly then move to the next piece of the XML which should be the “QUESTIONS” tag however it falls back through the same conditions as the “DateOfLastUpdate” tag, and when the data is printed to the screen the ‘blank’ entry shows up as “670069BA”. This also happens when i try to read each of the questions. Any ideas what i could be doing wrong? I am working in VS 2008 with the Qt 4.7.1 libraries and VS addin 1.1.7
Thanks for any help.
[EDIT: code formatting, Volker]
3 replies
Your GetDataString() method has an invalid signature. Do you return a pointer to a QString?
Also, according to the QXmlStream Bookmarks Example (in the Qt sources in examples/xml/streambookmarks) the authors use readNextStartElement() and readElementText() to extract the data. I’d suggest to try it this way.
Also, it would be helpful if you could provide us a compilable and running example to be able to reproduce the error locally.
Volker, Thank you so much for getting back to me. Yes that was a typo on the GetDataString() signature. I tried the two mods that you mentioned and that didn’t change anything, i still get the wierd blank spaces.
here is the text of the .cpp file that reads and writes the xml:
- #include "user.h"
- #include <QXmlStreamWriter>
- const QString DCPConfigController::CONFIG_FILE(tr("C:/Development/build/config/DailyCheck.config"));
- {
- }
- DCPConfigController::~DCPConfigController()
- {
- }
- {
- return mUserQuestions->keys();
- }
- {
- if(mUserQuestions->contains(aUser))
- {
- return mUserQuestions->value(aUser).Questions();
- }
- else
- {
- }
- }
- {
- if (mUserQuestions->contains(aUser))
- {
- if(mUserQuestions->value(aUser).Questions() == aUsersQuestions)
- {
- return;
- }
- else
- {
- mUserQuestions->remove(aUser);
- }
- }
- User tUser;
- tUser.UserName(aUser);
- tUser.Questions(aUsersQuestions);
- mUserQuestions->insert(aUser, tUser);
- }
- void DCPConfigController::ReadConfigFile()
- {
- mUserQuestions->clear();
- {
- //add code to log problem.
- return;
- }
- User* tUser = 0;
- while (!tReader.atEnd())
- {
- tReader.readNextStartElement();
- {
- if (tReader.name() == USER_TAG)
- {
- tUser = ParseUser(tReader, tUserName);
- mUserQuestions->insert(tUserName, *tUser);
- }
- }
- }
- tFile.close();
- }
- void DCPConfigController::WriteConfigFile()
- {
- {
- //add code to log problem.
- return;
- }
- tWriter.setAutoFormatting(true);
- tWriter.writeStartDocument();
- tWriter.writeStartElement(CHECK_TAG);
- {
- int tRowNum = 0;
- User tUser = mUserQuestions->value(tUserName);
- tWriter.writeStartElement(USER_TAG);
- tWriter.writeAttribute(ID_TAG, tUserName);
- tWriter.writeTextElement(LAST_UPDATE_TAG, tUser.LastUpdate());
- tWriter.writeStartElement(QUESTION_AREA_TAG);
- {
- tWriter.writeStartElement(QUESTION_TAG);
- tWriter.writeCharacters(tQuestion);
- tWriter.writeEndElement(); //end a question
- tRowNum++;
- }
- tWriter.writeEndElement(); // end the users questions
- tWriter.writeEndElement(); //ens the user
- }
- tWriter.writeEndElement();//ends the check
- tWriter.writeEndDocument();
- tFile.close();
- }
- {
- aReader.readNextStartElement();
- User* tUser = new User();
- tUser->UserName(aUserName);
- {
- if(aReader.name() == LAST_UPDATE_TAG && !aReader.isWhitespace())
- {
- tUser->LastUpdate(GetDataString(aReader));
- }
- if (aReader.name() == QUESTION_AREA_TAG && !aReader.isWhitespace())
- {
- tUser->Questions(ParseQuestions(aReader));
- }
- aReader.readNextStartElement();
- }
- return tUser;
- }
- {
- aReader.readNextStartElement();
- QStringList tQuestions;
- while(!(aReader.tokenType() == QXmlStreamReader::EndElement && aReader.name() == QUESTION_AREA_TAG))
- {
- if (aReader.name() == QUESTION_TAG && !aReader.isWhitespace())
- {
- tQuestions.append(GetDataString(aReader));
- }
- aReader.readNextStartElement();
- }
- return tQuestions;
- }
- {
- if(!aReader.isStartElement())
- {
- }
- // aReader.readNextStartElement();
- return aReader.readElementText();
- }
Here is the user .h file. The .cpp file only has the default constructor and destructor.
- #ifndef USER_H
- #define USER_H
- #include <QString>
- #include <QStringList>
- #include <QDateTime>
- class User
- {
- public:
- User();
- ~User();
- private:
- QString mUserName;
- QString mLastUpdate;
- QStringList mQuestions;
- };
- #endif // USER_H
[EDIT: code formatting – please use @-Tags, Volker]
Sorry, still not a short, complete, compilable example.
- short: Leave out anything that is not necessary to reproduce the problem (eg. writing stuff, when the problem is in the reading part)
- complete + compilable: all files needed to produce an executable that demonstrates the error. This does include the necessary header files and – in Qt world – a project file, and – if used – the data files.
Nothing less. Nothing more. No platform dependend paths. Use paths relative to your executable.
Please understand, that we do not have time nor find it funny to create header files for some random class we are supposed to analyze.
Regarding your code, after a short look:
If you call readNextStartElement() you need not check the token type. It is always of type QXmlStreamReader::StartElement.
Also, stick to one type of read: Either readNextStartElement() + readElementText() (and attributes() of course) or do readNext() and peek the contents manually.
You did not have a look at the mentioned streambookmarks example, did you? You can apply the techniques demonstrated there almost one-to-one to your project. You must be brave enough to wipe out your old code and start from scratch, though.
You must log in to post a reply. Not a member yet? Register here!


