In Qt 5.1, I'm having an issue with QXMLStreamReader waiting for a QProcess to produce more data.
If I read lines from an unbuffered QProcess, it works fine:
while(!vupProcess.state() == QProcess::NotRunning)
{
if (vupProcess.atEnd())
{
vupProcess.waitForReadyRead();
}
qDebug() << vupProcess.readLine();
}
It's pretty clear cut: when the buffer is out of data, it waits until there is more. When there is more, it will print lines without waiting.
Now, if I want to do the same with QXMLStreamReader, it works, but the processing of the XML elements happens at the wrong moment (too late).
Consider this:
QXmlStreamReader xml;
xml.setDevice(&vupProcess);
QStack<VUPDevice *> deviceStack;
QXmlStreamReader::TokenType tokenType = QXmlStreamReader::NoToken;
while (tokenType != QXmlStreamReader::EndDocument && !xml.hasError())
{
if (xml.device()->atEnd())
{
xml.device()->waitForReadyRead(XML_READNEXT_TIMEOUT);
}
tokenType = xml.readNext();
if (xml.hasError())
{
qDebug() << "ERROR";
return;
}
...
}
By the time waitForReadyRead(int)
is called, a lot of elements are available already, and I need them processed to update the GUI. However, it won't continue until the QProcess starts to output more. It seems to be because the underlying QProcess is read till it's empty as fast as possible, and then my parser unnecessarily hangs in the early stages, because the QProcess doesn't output anymore.
What I need, is xml.hasMoreElements()
, so that I can make:
if (xml.device()->atEnd() && !xml.hasMoreElements())
{
xml.device()->waitForReadyRead(XML_READNEXT_TIMEOUT);
}
But I can't seem to find an API call that does this for me.
So, how do I not wait for more data when it's not necessery?
I guess I solved it. There is no method for asking if there ar more XML elements, but the readNext()
call will put the QXMLStreamReader
object in a state you can detect, and use to have the back-end device wait:
QXmlStreamReader::TokenType tokenType = xml.readNext();
while (xml.error() == QXmlStreamReader::PrematureEndOfDocumentError)
{
xml.device()->waitForReadyRead(XML_READNEXT_TIMEOUT);
tokenType = xml.readNext();
}
if (xml.hasError())
{
...
}