QXmlStreamReader throws error when reading a sub element
-
Hello everyone,
I've tried to read an xml file with the QXmlStreamReader (with Qt6) but I always stumble on the same problem:
the error "Expected character data" is thrown as soon as the first sub element is read.Here is an extract of the xml file:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>Aapi</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Aapi</name> <description>Personnal test project</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> etc ...
Here is how I set the QXmlStreamReader:
QFile pom(pomPath); if(!pom.open(QIODevice::ReadOnly)) { qWarning() << "pom.xml could not be opened:" << pom.errorString(); } QXmlStreamReader xmlReader(&pom);
For testing purposes i've tried very simple loop in order to read the entire file:
while (!xmlReader.atEnd()) { xmlReader.readNextStartElement(); qDebug() << xmlReader.readElementText(); }
Will throw: "Expected character data" at line: 5 column: 15
Or:
while(xmlReader.readNextStartElement()) { qDebug() << xmlReader.name(); }
No error thrown but will also stop at modelVersion (line 5).
Catching errors:
if (xmlReader.hasError()) { qDebug() << "Error:" << xmlReader.errorString() << "at line:" << xmlReader.lineNumber() << "column:" << xmlReader.columnNumber(); }
At some point I've thought the problem came from the fact that the modelVersion tag only contains numbers but even if I comment it out, QXmlStreamReader will stop on the next line.
After reading the documentations and a lot of forum post etc... I'm starting to running out of ideas and still don't understand where the problem is comming from.
Am I missing something ?Thank you for reading.
Have a nice day. -
As expected readElementText() cannot read "complete" (tag and content) child elements.
However it is possible to ignore child element or to get only their content by using QXmlStreamReader::ReadElementTextBehaviour enum as parameter.
Unfortunately this does not provide a straight forward solution to my problem so I had to found a workaround.
For example I want to get all the child elements of the project tag (and ignore all grandchildren):
while (!xmlReader.atEnd()) { QXmlStreamReader::TokenType token = xmlReader.readNext(); qDebug() << "Next token:" << token << xmlReader.tokenString() << "- at line:" << xmlReader.lineNumber() << "- name:" << xmlReader.name(); if(token == QXmlStreamReader::StartElement && xmlReader.name() == QString("project")) { xmlReader.readNext(); while(xmlReader.name() != QString("project")) { xmlReader.readNextStartElement(); qDebug() << "- tag:" << xmlReader.name() << "- content:" << xmlReader.readElementText(QXmlStreamReader::SkipChildElements); } } }
Although it's working it is not very elegant and might not be really reusable (e.g. to get the dependencies in a pom.xml file).
Thank you for reading.
Have a nice day. -
Hello everyone,
I've tried to read an xml file with the QXmlStreamReader (with Qt6) but I always stumble on the same problem:
the error "Expected character data" is thrown as soon as the first sub element is read.Here is an extract of the xml file:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>Aapi</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Aapi</name> <description>Personnal test project</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> etc ...
Here is how I set the QXmlStreamReader:
QFile pom(pomPath); if(!pom.open(QIODevice::ReadOnly)) { qWarning() << "pom.xml could not be opened:" << pom.errorString(); } QXmlStreamReader xmlReader(&pom);
For testing purposes i've tried very simple loop in order to read the entire file:
while (!xmlReader.atEnd()) { xmlReader.readNextStartElement(); qDebug() << xmlReader.readElementText(); }
Will throw: "Expected character data" at line: 5 column: 15
Or:
while(xmlReader.readNextStartElement()) { qDebug() << xmlReader.name(); }
No error thrown but will also stop at modelVersion (line 5).
Catching errors:
if (xmlReader.hasError()) { qDebug() << "Error:" << xmlReader.errorString() << "at line:" << xmlReader.lineNumber() << "column:" << xmlReader.columnNumber(); }
At some point I've thought the problem came from the fact that the modelVersion tag only contains numbers but even if I comment it out, QXmlStreamReader will stop on the next line.
After reading the documentations and a lot of forum post etc... I'm starting to running out of ideas and still don't understand where the problem is comming from.
Am I missing something ?Thank you for reading.
Have a nice day.@Aymeric_Qt
For a start, check the return result fromreadNextStartElement()
.Then try something other than
readElementText()
. That (tries to) read the whole of the element, do a bit at a time withreadNext()
or similar.Then try your code on some tiny XML.
Finally, I don't use (or trust) Qt6, don't suppose you can text on Qt5 instead?
-
Hello @JonB,
Thanks for your reply.
I have forgot to mention in my first message that indeed readNextStartElement() returns true (and then false which seems normal).
Concerning readElementText() I have to use it because I want to retrieve the value beteween the tags and readNext only returns the next token type.
As you suggested I've tried with a much smaller and simpler xml but I encouter the same problems.
Concerning the version of Qt it is 6.2.0 so I supposed it is a fairly stable version but is it to early to go with Qt 6 yet ?
As my project is at the very beginning it is not a big deal to redo on Qt5. -
Hello @JonB,
Thanks for your reply.
I have forgot to mention in my first message that indeed readNextStartElement() returns true (and then false which seems normal).
Concerning readElementText() I have to use it because I want to retrieve the value beteween the tags and readNext only returns the next token type.
As you suggested I've tried with a much smaller and simpler xml but I encouter the same problems.
Concerning the version of Qt it is 6.2.0 so I supposed it is a fairly stable version but is it to early to go with Qt 6 yet ?
As my project is at the very beginning it is not a big deal to redo on Qt5.@Aymeric_Qt said in QXmlStreamReader throws error when reading a sub element:
Concerning readElementText() I have to use it because I want to retrieve the value beteween the tags and readNext only returns the next token type.
The point is to test by using
readNext
, not your final solution. You are trying to discover where/why you are getting an error.Here is the XML I might start from
<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> </project>
That's what "tiny" means. Does that work for you, no error on
readElementText()
? Assuming so, build back up toward your desired input. -
@Aymeric_Qt said in QXmlStreamReader throws error when reading a sub element:
Concerning readElementText() I have to use it because I want to retrieve the value beteween the tags and readNext only returns the next token type.
The point is to test by using
readNext
, not your final solution. You are trying to discover where/why you are getting an error.Here is the XML I might start from
<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> </project>
That's what "tiny" means. Does that work for you, no error on
readElementText()
? Assuming so, build back up toward your desired input.Yes when I said ' I've tried with a much smaller and simpler xml' this is excactly the xml file I've created (just project and model version tags).
And readnext() return a 4 (which is QXmlStreamReader::StartElement token type) on line 3
and then the error occurs: "Expected character data" at line: 3 column: 10". -
Yes when I said ' I've tried with a much smaller and simpler xml' this is excactly the xml file I've created (just project and model version tags).
And readnext() return a 4 (which is QXmlStreamReader::StartElement token type) on line 3
and then the error occurs: "Expected character data" at line: 3 column: 10".@Aymeric_Qt said in QXmlStreamReader throws error when reading a sub element:
and then the error occurs: "Expected character data" at line: 3 column: 10".
And then when you call what does the error occur? Please answer clearly. I am trying to determine whether that comes from
readNext()
or only fromreadElementText()
?I said earlier:
Then try something other than
readElementText()
. That (tries to) read the whole of the element, do a bit at a time withreadNext()
or similar. -
@Aymeric_Qt said in QXmlStreamReader throws error when reading a sub element:
and then the error occurs: "Expected character data" at line: 3 column: 10".
And then when you call what does the error occur? Please answer clearly. I am trying to determine whether that comes from
readNext()
or only fromreadElementText()
?I said earlier:
Then try something other than
readElementText()
. That (tries to) read the whole of the element, do a bit at a time withreadNext()
or similar.Sorry if my previous message was confusing.
The error occurs when the readElementText() is called.@Aymeric_Qt said in QXmlStreamReader throws error when reading a sub element:
For testing purposes i've tried very simple loop in order to read the entire file:
while (!xmlReader.atEnd())
{
xmlReader.readNextStartElement();
qDebug() << xmlReader.readElementText();
}Will throw: "Expected character data" at line: 5 column: 15
If I only use readNext() it runs fine to the end of the file without any error.
Here is 2 tests I've made:Xml test file:
<?xml version="1.0" encoding="UTF-8"?> <project> <version>thisversion</version> </project>
First loop (readNext() - no error):
while (!xmlReader.atEnd()) { QXmlStreamReader::TokenType token = xmlReader.readNext(); qDebug() << "readNext():" << token << "- at line:" << xmlReader.lineNumber(); }
Console output:
readNext(): 2 - at line: 1 readNext(): 4 - at line: 2 readNext(): 6 - at line: 3 readNext(): 4 - at line: 3 readNext(): 6 - at line: 3 readNext(): 5 - at line: 3 readNext(): 6 - at line: 4 readNext(): 5 - at line: 4 readNext(): 3 - at line: 4
Second loop (readElementText() - error):
while (!xmlReader.atEnd()) { xmlReader.readNext(); qDebug() << xmlReader.readElementText(); }
Console output:
"" "\n\t" Error: "Expected character data." at line: 3 column: 10 ()
-
Sorry if my previous message was confusing.
The error occurs when the readElementText() is called.@Aymeric_Qt said in QXmlStreamReader throws error when reading a sub element:
For testing purposes i've tried very simple loop in order to read the entire file:
while (!xmlReader.atEnd())
{
xmlReader.readNextStartElement();
qDebug() << xmlReader.readElementText();
}Will throw: "Expected character data" at line: 5 column: 15
If I only use readNext() it runs fine to the end of the file without any error.
Here is 2 tests I've made:Xml test file:
<?xml version="1.0" encoding="UTF-8"?> <project> <version>thisversion</version> </project>
First loop (readNext() - no error):
while (!xmlReader.atEnd()) { QXmlStreamReader::TokenType token = xmlReader.readNext(); qDebug() << "readNext():" << token << "- at line:" << xmlReader.lineNumber(); }
Console output:
readNext(): 2 - at line: 1 readNext(): 4 - at line: 2 readNext(): 6 - at line: 3 readNext(): 4 - at line: 3 readNext(): 6 - at line: 3 readNext(): 5 - at line: 3 readNext(): 6 - at line: 4 readNext(): 5 - at line: 4 readNext(): 3 - at line: 4
Second loop (readElementText() - error):
while (!xmlReader.atEnd()) { xmlReader.readNext(); qDebug() << xmlReader.readElementText(); }
Console output:
"" "\n\t" Error: "Expected character data." at line: 3 column: 10 ()
@Aymeric_Qt said in QXmlStreamReader throws error when reading a sub element:
If I only use readNext() it runs fine to the end of the file without any error.
It seems to have taken me about six times of asking to extract this vital piece of information from you! I did say right from the start to use only
readNext()
while you figured out what was the issue, just a standard debugging/development technique.So now you have your answer: go look at the source of
readElementText()
, say on woboq, and figure what it is doing/why it is raising an error. See https://doc.qt.io/qt-5.15/qxmlstreamreader.html#readElementText for the behaviour parameter you may want to play with to see what is going on.If it's a whitespace issue --- and I don't know whether it is --- you might try with XML:
<?xml version="1.0" encoding="UTF-8"?><project><modelVersion>4.0.0</modelVersion></project>
to see if that makes any difference.
-
As expected readElementText() cannot read "complete" (tag and content) child elements.
However it is possible to ignore child element or to get only their content by using QXmlStreamReader::ReadElementTextBehaviour enum as parameter.
Unfortunately this does not provide a straight forward solution to my problem so I had to found a workaround.
For example I want to get all the child elements of the project tag (and ignore all grandchildren):
while (!xmlReader.atEnd()) { QXmlStreamReader::TokenType token = xmlReader.readNext(); qDebug() << "Next token:" << token << xmlReader.tokenString() << "- at line:" << xmlReader.lineNumber() << "- name:" << xmlReader.name(); if(token == QXmlStreamReader::StartElement && xmlReader.name() == QString("project")) { xmlReader.readNext(); while(xmlReader.name() != QString("project")) { xmlReader.readNextStartElement(); qDebug() << "- tag:" << xmlReader.name() << "- content:" << xmlReader.readElementText(QXmlStreamReader::SkipChildElements); } } }
Although it's working it is not very elegant and might not be really reusable (e.g. to get the dependencies in a pom.xml file).
Thank you for reading.
Have a nice day.