PDA

View Full Version : QXmlStreamReader and PrematureEndOfDocumentError



SABROG
15th July 2009, 21:14
I have this code like this:



bool XmlSpoListParser::read()
{
while (!atEnd()) {
readNext();

if (isStartElement()) {
if (name() == QLatin1String("Tag") && attributes().value(QLatin1String("version")) == QLatin1String("1.0")) {
readSomething1();
break;
} else {
raiseError(QObject::tr("The file is not an Tag version 1.0 file."));
break;
}
}
if (hasError() && onError()) {
break;
}
}

return !error();
}

bool XmlSpoListParser::onError()
{
if (error() == QXmlStreamReader::PrematureEndOfDocumentError) {
appendMoreData();
return false;
} else {
qDebug() << errorString();
return true;
}
}

void XmlSpoListParser::appendMoreData()
{
//???
}

void XmlSpoListParser::readSomething1()
{
while (!(isEndElement() && name() == QLatin1String("Tag2")) && !atEnd()) {
readNext();
if (isStartElement()) {
if (name() == QLatin1String("Tag3")) {
readSomething2();
} else {
skipSubTree();
}
}
if (hasError() && onError()) {
break;
}
}
}

void XmlSpoListParser::readSomething2()
{
while (!(isEndElement() && name() == QLatin1String("Tag3")) && !atEnd()) {
readNext();
if (isStartElement()) {
if (name() == QLatin1String("Tag4")) {
readSomething3();
} else {
skipSubTree();
}
}
if (hasError() && onError()) {
break;
}
}
}


How i can wait data from socket when error PrematureEndOfDocumentError occured from readSomething2() method (for example)? I wan't call addData() to parser and return back to method readSomething1() after new data arrived. What i must do, create additional QEventLoop in method appendMoreData, or use infinite while(1) with QApplication::processEvents() or what?

jpn
16th July 2009, 13:47
Quoting QXmlStreamReader docs:


Incremental parsing

QXmlStreamReader is an incremental parser. It can handle the case where the document can't be parsed all at once because it arrives in chunks (e.g. from multiple files, or over a network connection). When the reader runs out of data before the complete document has been parsed, it reports a PrematureEndOfDocumentError. When more data arrives, either because of a call to addData() or because more data is available through the network device(), the reader recovers from the PrematureEndOfDocumentError error and continues parsing the new data with the next call to readNext().

For example, if you read data from the network using QHttp, you would connect its readyRead() signal to a custom slot. In this slot, you read all available data with readAll() and pass it to the XML stream reader using addData(). Then you call your custom parsing function that reads the XML events from the reader.

SABROG
16th July 2009, 14:18
When more data arrives, either because of a call to addData() or because more data is available through the network device(), the reader recovers from the PrematureEndOfDocumentError error and continues parsing the new data with the next call to readNext().

I test QBuffer and QFile as device() and each time when i try use addData() i get error in console about using device(). I don't know, may be if device has been socket may all be allright, but i don't think what this solved problem when parser must return execute after error() with PrematureEndOfDucumentError. error() just exit from all while()'s and no chance restore parsing.


For example, if you read data from the network using QHttp, you would connect its readyRead() signal to a custom slot. In this slot, you read all available data with readAll() and pass it to the XML stream reader using addData(). Then you call your custom parsing function that reads the XML events from the reader.

How readyRead() can help restore parser execute from last context? For this situation we must have while(1) for wait readyReady or reparsing previous xml with new data from beginning.

SABROG
17th July 2009, 16:53
I checkout parser with socket. Documentation is lie or i do something wrong:



For example, if you read data from the network using QHttp, you would connect its readyRead() signal to a custom slot. In this slot, you read all available data with readAll() and pass it to the XML stream reader using addData(). Then you call your custom parsing function that reads the XML events from the reader.


When i run program i get:



QXmlStreamReader: addData() with device()


in console. Inside parser i set device as:



void MainWindow::onConnectionEstablished() {
qDebug() << "Connection established!";
if (!reader.read(socket)) {
...
bool XmlSpoListParser::read(QIODevice *device) {
setDevice(device);




void MainWindow::readIncomingData()
{
qDebug() << "Get: " << socket->size() << " bytes.";
reader.addData(socket->readAll());
}


If i remove setDevice() and write this code all work fine:



void MainWindow::readIncomingData() {
qDebug() << "Get: " << socket->size() << " bytes.";
reader.addData(socket->readAll());
reader.loop.quit();
}
...
class XmlSpoListParser : public QXmlStreamReader {
public:
XmlSpoListParser();
bool read(QIODevice *);
bool read();
QEventLoop loop;

...
void XmlSpoListParser::appendMoreData() {
loop.exec();
}





bool XmlSpoListParser::onError() {
if (error() == QXmlStreamReader::PrematureEndOfDocumentError) {
appendMoreData();
return false;
} else {
qDebug() << errorString();
return true;
}
}


But code with QEventLoop looks ugly. How right?