Query Regarding QXmlStreamReader API
-
This code is based on QT 5.14.1 (MSVC 2017,32 bit) and Qt Creator version is 4.11.1
I am trying to read following XML -
<?xml version="1.0" encoding="UTF-8"?> <CBI_CONFIGURATION> <Input> <CardInput> <Card Id = "1" IP = "192.168.10.2" Max_Bits = "16"> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> <Details Bit_Position = "4" Name = "L_P03.S09ERQ" Type = "Non-Vital"/> </Card> <Card Id = "2" IP="92.168.1.2" Max_Bits = "32"> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> </Card> </CardInput> </Input> </CBI_CONFIGURATION>
code for reading xml is
my class is
class xmlDataExtractor { public: QFile file; xmlDataExtractor(QString xmlFilePath); bool parseXml(); bool read(); static inline QString idAttribute() { return QStringLiteral("Id"); } static inline QString idenAttribute() { return QStringLiteral("IDEN"); } static inline QString indexAttribute() { return QStringLiteral("index"); } static inline QString nameAttribute() { return QStringLiteral("Name"); } static inline QString typeAttribute() { return QStringLiteral("Type"); } private: QXmlStreamReader xml; void readInput(); void readCardInput(); void readCard(); void readDetails(); };
Function definitions are
bool xmlDataExtractor::parseXml() { while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("Input")) readInput(); else xml.skipCurrentElement(); } return true; } void xmlDataExtractor::readInput() { while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("CardInput")) readCardInput(); else xml.skipCurrentElement(); } } void xmlDataExtractor::readCardInput() { while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("Card")) readCard(); else xml.skipCurrentElement(); } } void xmlDataExtractor::readCard() { int cardId = xml.attributes().value(idAttribute()).toInt(); QString cardIp = xml.attributes().value(ipAttribute()).toString(); int maxBits = xml.attributes().value(maxbitsAttribute()).toInt(); qDebug()<<"Card:-> Id["<<cardId<<"] \tIp["<<cardIp<<"] \tmaxBits["<<maxBits<<"]"<<endl; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("Details")) readDetails(); else xml.skipCurrentElement(); } } void xmlDataExtractor::readDetails() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); #ifdef DETAILS_HAVE_ATTRIBUTE QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"<<endl; #else QString text = xml.readElementText(); qDebug()<<text<<endl; #endif }
Problem is : while reading detail element:
Case 1: if Details element has attributes then code just read first Details element , and than statement while (xml.readNextStartElement()) of function void xmlDataExtractor::readCard() return false when it executes 2nd time.
if detail is in this way in XML than DETAILS_HAVE_ATTRIBUTE is defined
<Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details>
<Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details>Case 2: if Details element do not have any attribute, just information than it will read first time as well as all the <details> elements i.e. same code works fine .
if detail is in this way in XML than DETAILS_HAVE_ATTRIBUTE is not defined
<Details> Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"> </Details>So question is
why xml.readNextStartElement() statement behaves differently in Details in xmlDataExtractor::readCard() function?Please help me to understand the issue.
-
@ChrisW67 Thanks Chris, actually I have put that preprocessor directive to bifurcate the read details implementation.
so if I understood you right than you are using following code
void xmlDataExtractor::readDetails() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"<<endl; QString text = xml.readElementText(); qDebug()<<text<<endl; }
As details tag is like
<Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details>
But I am using this part of code-
// details tag with attribute and no text data void xmlDataExtractor::readDetails() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"<<endl; }
i.e. without QString text = xml.readElementText(); as it it not needed. Request to remove this line from your code too. than you will find , it is not reading.
While fixing this , I have to include QString text = xml.readElementText(); in code, but why it is needed when detail tag does not have any text information.when detail tag is like - (with out attribute )
<Details>Text 1</Details> <Details>text2</Details>
than my implementation is
void xmlDataExtractor::readDetails() { QString text = xml.readElementText(); qDebug()<<text<<endl; }
in this case code works just fine.
So why in 1st case, without adding QString text = xml.readElementText(); code is not able to read detail tag with attribute.
I hope , now the issue will be clear to you.
Please once read again the thread, if problem is still not clear.
By the way, thank for your efforts and answers.@belcsns said in Query Regarding QXmlStreamReader API:
But I am using this part of code
I think everyone except you read your original post as, "if the data changes (i.e. removing attributes) the behaviour changes", not "if the code changes, the behaviour changes." The first is a run-time input issue, the second is self-evident.
Posting a small, self-contained program that demonstrates the problem is invaluable. Firstly, it often leads to discovering your own solution, and secondly it expresses the problem concretely. This caused confusion right from day one and prompted @SGaist's question about the conditional compilation.
Now that we know exactly what your code looks like...
If you do not call readElementText(), skipCurrentElement(), or otherwise process the content of the <Details> element to completion then the current element is <Details> when you exit this function and return to readCardInput(). You then call readNextStartElement(), which is documented thus (emphasis mine):
Reads until the next start element within the current element. Returns true when a start element was reached. When the end element was reached, or when an error occurred, false is returned.
So, readNextStartElement() consumes the remainder of the current <Details> element, returns false, and leaves the current element as </Details>. If the while loop did not terminate at that point, and you called readDetails() again I would expect the Q_ASSERT to fail.
@belcsns said in Query Regarding QXmlStreamReader API:
So question is
why xml.readNextStartElement() statement behaves differently in Details in xmlDataExtractor::readCard() function?readNextStartElement() is behaving as documented but its input has changed.
-
Hi,
Why are you using a pre-processor macro for what seems to be a condition that depends on the doucement you read ?
-
@SGaist : Thanks ,This Macro is just used for clarification here who is reading this issue. In actual code it is not used.
That xml file in which detail contains attributes than that function code is applied.
& When xml file in which detail does not contains attribute , contains only information than that other section of function code is applied. (means implementation of xmlDataExtractor::readDetails() function )Issue is why the while loop which is used in xmlDataExtractor::readCard() function runs properly and read all details tag data if it does not have any attribute
but if it contains any attribute than first xml.readNextStartElement() reuturn false and next time it returns true. -
@SGaist : Thanks ,This Macro is just used for clarification here who is reading this issue. In actual code it is not used.
That xml file in which detail contains attributes than that function code is applied.
& When xml file in which detail does not contains attribute , contains only information than that other section of function code is applied. (means implementation of xmlDataExtractor::readDetails() function )Issue is why the while loop which is used in xmlDataExtractor::readCard() function runs properly and read all details tag data if it does not have any attribute
but if it contains any attribute than first xml.readNextStartElement() reuturn false and next time it returns true.@belcsns It would have helped if the code you posted was complete, consistent, and compilable. Having done the minimum to make it compile I had no problems with your input file:
#include <QCoreApplication> #include <QDebug> #include <QFile> #include <QXmlStreamReader> class xmlDataExtractor { public: QFile file; xmlDataExtractor(QString xmlFilePath); bool parseXml(); bool read(); static inline QString idAttribute() { return QStringLiteral("Id"); } static inline QString idenAttribute() { return QStringLiteral("IDEN"); } static inline QString indexAttribute() { return QStringLiteral("index"); } static inline QString nameAttribute() { return QStringLiteral("Name"); } static inline QString typeAttribute() { return QStringLiteral("Type"); } // Added to make compilable static inline QString ipAttribute() { return QStringLiteral("IP"); } static inline QString maxbitsAttribute() { return QStringLiteral("Max_Bits"); } static inline QString bitPositionAttribute() { return QStringLiteral("Bit_Position"); } // End additions private: QXmlStreamReader xml; void readInput(); void readCardInput(); void readCard(); void readDetails(); }; // Added to make compilable xmlDataExtractor::xmlDataExtractor(QString xmlFilePath) { file.setFileName(xmlFilePath); } bool xmlDataExtractor::read() { qDebug() << "Opening" << file.fileName(); if (file.open(QIODevice::ReadOnly)) { xml.setDevice(&file); xml.readNextStartElement(); return parseXml(); } else { qDebug() << "Cannot open" << file.fileName(); return false; } } // end addition bool xmlDataExtractor::parseXml() { qDebug() << Q_FUNC_INFO; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("Input")) readInput(); else xml.skipCurrentElement(); } return true; } void xmlDataExtractor::readInput() { qDebug() << Q_FUNC_INFO; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("CardInput")) readCardInput(); else xml.skipCurrentElement(); } } void xmlDataExtractor::readCardInput() { qDebug() << Q_FUNC_INFO; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("Card")) readCard(); else xml.skipCurrentElement(); } } void xmlDataExtractor::readCard() { qDebug() << Q_FUNC_INFO; int cardId = xml.attributes().value(idAttribute()).toInt(); QString cardIp = xml.attributes().value(ipAttribute()).toString(); int maxBits = xml.attributes().value(maxbitsAttribute()).toInt(); qDebug()<<"Card:-> Id["<<cardId<<"] \tIp["<<cardIp<<"] \tmaxBits["<<maxBits<<"]"; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("Details")) readDetails(); else xml.skipCurrentElement(); } } void xmlDataExtractor::readDetails() { qDebug() << Q_FUNC_INFO; Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"; QString text = xml.readElementText(); qDebug()<<text; } int main(int argc, char **argv) { QCoreApplication app(argc, argv); xmlDataExtractor x("test.xml"); x.read(); return 0; }
Your example input contains no Details elements without attributes, so I added two:
<?xml version="1.0" encoding="UTF-8"?> <CBI_CONFIGURATION> <Input> <CardInput> <Card Id = "1" IP = "192.168.10.2" Max_Bits = "16"> <Details>no attributes</Details> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> <Details Bit_Position = "4" Name = "L_P03.S09ERQ" Type = "Non-Vital"/> </Card> <Card Id = "2" IP="92.168.1.2" Max_Bits = "32"> <Details/> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> </Card> </CardInput> </Input> </CBI_CONFIGURATION>
and the output
Opening "test.xml" Card:-> Id[ 1 ] Ip[ "192.168.10.2" ] maxBits[ 16 ] Details: bitPosition[ 0 ] Name[ "" ] Type[ "" ] "no attributes" Details: bitPosition[ 1 ] Name[ "L_P03_04ENPB" ] Type[ "Non-Vital" ] "" Details: bitPosition[ 2 ] Name[ "L_S03E.S01FRQ" ] Type[ "Vital" ] "" Details: bitPosition[ 3 ] Name[ "L_S06E.S08FRQ" ] Type[ "Vital" ] "" Details: bitPosition[ 4 ] Name[ "L_P03.S09ERQ" ] Type[ "Non-Vital" ] "" Card:-> Id[ 2 ] Ip[ "92.168.1.2" ] maxBits[ 32 ] Details: bitPosition[ 0 ] Name[ "" ] Type[ "" ] "" Details: bitPosition[ 1 ] Name[ "L_P03_04ENPB" ] Type[ "Non-Vital" ] "" Details: bitPosition[ 2 ] Name[ "L_S03E.S01FRQ" ] Type[ "Vital" ] "" Details: bitPosition[ 3 ] Name[ "L_S06E.S08FRQ" ] Type[ "Vital" ] ""
Perhaps you want to explain what the problem actually is.
-
@belcsns It would have helped if the code you posted was complete, consistent, and compilable. Having done the minimum to make it compile I had no problems with your input file:
#include <QCoreApplication> #include <QDebug> #include <QFile> #include <QXmlStreamReader> class xmlDataExtractor { public: QFile file; xmlDataExtractor(QString xmlFilePath); bool parseXml(); bool read(); static inline QString idAttribute() { return QStringLiteral("Id"); } static inline QString idenAttribute() { return QStringLiteral("IDEN"); } static inline QString indexAttribute() { return QStringLiteral("index"); } static inline QString nameAttribute() { return QStringLiteral("Name"); } static inline QString typeAttribute() { return QStringLiteral("Type"); } // Added to make compilable static inline QString ipAttribute() { return QStringLiteral("IP"); } static inline QString maxbitsAttribute() { return QStringLiteral("Max_Bits"); } static inline QString bitPositionAttribute() { return QStringLiteral("Bit_Position"); } // End additions private: QXmlStreamReader xml; void readInput(); void readCardInput(); void readCard(); void readDetails(); }; // Added to make compilable xmlDataExtractor::xmlDataExtractor(QString xmlFilePath) { file.setFileName(xmlFilePath); } bool xmlDataExtractor::read() { qDebug() << "Opening" << file.fileName(); if (file.open(QIODevice::ReadOnly)) { xml.setDevice(&file); xml.readNextStartElement(); return parseXml(); } else { qDebug() << "Cannot open" << file.fileName(); return false; } } // end addition bool xmlDataExtractor::parseXml() { qDebug() << Q_FUNC_INFO; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("Input")) readInput(); else xml.skipCurrentElement(); } return true; } void xmlDataExtractor::readInput() { qDebug() << Q_FUNC_INFO; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("CardInput")) readCardInput(); else xml.skipCurrentElement(); } } void xmlDataExtractor::readCardInput() { qDebug() << Q_FUNC_INFO; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("Card")) readCard(); else xml.skipCurrentElement(); } } void xmlDataExtractor::readCard() { qDebug() << Q_FUNC_INFO; int cardId = xml.attributes().value(idAttribute()).toInt(); QString cardIp = xml.attributes().value(ipAttribute()).toString(); int maxBits = xml.attributes().value(maxbitsAttribute()).toInt(); qDebug()<<"Card:-> Id["<<cardId<<"] \tIp["<<cardIp<<"] \tmaxBits["<<maxBits<<"]"; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("Details")) readDetails(); else xml.skipCurrentElement(); } } void xmlDataExtractor::readDetails() { qDebug() << Q_FUNC_INFO; Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"; QString text = xml.readElementText(); qDebug()<<text; } int main(int argc, char **argv) { QCoreApplication app(argc, argv); xmlDataExtractor x("test.xml"); x.read(); return 0; }
Your example input contains no Details elements without attributes, so I added two:
<?xml version="1.0" encoding="UTF-8"?> <CBI_CONFIGURATION> <Input> <CardInput> <Card Id = "1" IP = "192.168.10.2" Max_Bits = "16"> <Details>no attributes</Details> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> <Details Bit_Position = "4" Name = "L_P03.S09ERQ" Type = "Non-Vital"/> </Card> <Card Id = "2" IP="92.168.1.2" Max_Bits = "32"> <Details/> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> </Card> </CardInput> </Input> </CBI_CONFIGURATION>
and the output
Opening "test.xml" Card:-> Id[ 1 ] Ip[ "192.168.10.2" ] maxBits[ 16 ] Details: bitPosition[ 0 ] Name[ "" ] Type[ "" ] "no attributes" Details: bitPosition[ 1 ] Name[ "L_P03_04ENPB" ] Type[ "Non-Vital" ] "" Details: bitPosition[ 2 ] Name[ "L_S03E.S01FRQ" ] Type[ "Vital" ] "" Details: bitPosition[ 3 ] Name[ "L_S06E.S08FRQ" ] Type[ "Vital" ] "" Details: bitPosition[ 4 ] Name[ "L_P03.S09ERQ" ] Type[ "Non-Vital" ] "" Card:-> Id[ 2 ] Ip[ "92.168.1.2" ] maxBits[ 32 ] Details: bitPosition[ 0 ] Name[ "" ] Type[ "" ] "" Details: bitPosition[ 1 ] Name[ "L_P03_04ENPB" ] Type[ "Non-Vital" ] "" Details: bitPosition[ 2 ] Name[ "L_S03E.S01FRQ" ] Type[ "Vital" ] "" Details: bitPosition[ 3 ] Name[ "L_S06E.S08FRQ" ] Type[ "Vital" ] ""
Perhaps you want to explain what the problem actually is.
@ChrisW67 Hi Chris, Thanks, I had tried my best to explain the problem earlier itself. However the problem is ..void xmlDataExtractor::readDetails() which is to be used for reading details tag.
if details tag is defined in xml in following way
<Details>no attributes</Details> , code work properly. The loop condition of caller function, while (xml.readNextStartElement()) of void xmlDataExtractor::readCard() .But if details tag contains attribute like-
<Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/>
then this condition - of while while (xml.readNextStartElement()) behaves in following way-
for first time xml.readNextStartElement() return true --> reads first details tag
for 2nd time xml.readNextStartElement() return false.
for 3rd time xml.readNextStartElement() return true. --> reads second details tag
for 4th time xml.readNextStartElement() return false.just do one thing, in your xml , delete
<Details>no attributes</Details>
this line and than use the same code to run, you will get the problem.
share your implementation of .void xmlDataExtractor::readDetails() if you are not using mine.so the problem is same implementation of detail function works properly if tag does not contain any attribute.
but as soon as tag contains attribute , every even number of iteration returns false from code sectionvoid xmlDataExtractor::readCard() { //..... while (xml.readNextStartElement()) // this condition { //... } }
Question is why this behavior?
-
@ChrisW67 Hi Chris, Thanks, I had tried my best to explain the problem earlier itself. However the problem is ..void xmlDataExtractor::readDetails() which is to be used for reading details tag.
if details tag is defined in xml in following way
<Details>no attributes</Details> , code work properly. The loop condition of caller function, while (xml.readNextStartElement()) of void xmlDataExtractor::readCard() .But if details tag contains attribute like-
<Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/>
then this condition - of while while (xml.readNextStartElement()) behaves in following way-
for first time xml.readNextStartElement() return true --> reads first details tag
for 2nd time xml.readNextStartElement() return false.
for 3rd time xml.readNextStartElement() return true. --> reads second details tag
for 4th time xml.readNextStartElement() return false.just do one thing, in your xml , delete
<Details>no attributes</Details>
this line and than use the same code to run, you will get the problem.
share your implementation of .void xmlDataExtractor::readDetails() if you are not using mine.so the problem is same implementation of detail function works properly if tag does not contain any attribute.
but as soon as tag contains attribute , every even number of iteration returns false from code sectionvoid xmlDataExtractor::readCard() { //..... while (xml.readNextStartElement()) // this condition { //... } }
Question is why this behavior?
@belcsns I added those lines because you stated the program behaves differently when no attributes are present but your example contained no such lines. Anyway, my posted code with this input:
<?xml version="1.0" encoding="UTF-8"?> <CBI_CONFIGURATION> <Input> <CardInput> <Card Id = "1" IP = "192.168.10.2" Max_Bits = "16"> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> <Details Bit_Position = "4" Name = "L_P03.S09ERQ" Type = "Non-Vital"/> </Card> <Card Id = "2" IP="92.168.1.2" Max_Bits = "32"> <Details/> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> </Card> </CardInput> </Input> </CBI_CONFIGURATION>
The program outputs:
Opening "test.xml" bool xmlDataExtractor::parseXml() void xmlDataExtractor::readInput() void xmlDataExtractor::readCardInput() void xmlDataExtractor::readCard() Card:-> Id[ 1 ] Ip[ "192.168.10.2" ] maxBits[ 16 ] void xmlDataExtractor::readDetails() Details: bitPosition[ 1 ] Name[ "L_P03_04ENPB" ] Type[ "Non-Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 2 ] Name[ "L_S03E.S01FRQ" ] Type[ "Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 3 ] Name[ "L_S06E.S08FRQ" ] Type[ "Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 4 ] Name[ "L_P03.S09ERQ" ] Type[ "Non-Vital" ] "" void xmlDataExtractor::readCard() Card:-> Id[ 2 ] Ip[ "92.168.1.2" ] maxBits[ 32 ] void xmlDataExtractor::readDetails() Details: bitPosition[ 0 ] Name[ "" ] Type[ "" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 1 ] Name[ "L_P03_04ENPB" ] Type[ "Non-Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 2 ] Name[ "L_S03E.S01FRQ" ] Type[ "Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 3 ] Name[ "L_S06E.S08FRQ" ] Type[ "Vital" ] ""
That is, it has successfully read both Cards, all 8 Details records, all their attributes, and their body text (none actually present). I see no problem here.
-
@belcsns I added those lines because you stated the program behaves differently when no attributes are present but your example contained no such lines. Anyway, my posted code with this input:
<?xml version="1.0" encoding="UTF-8"?> <CBI_CONFIGURATION> <Input> <CardInput> <Card Id = "1" IP = "192.168.10.2" Max_Bits = "16"> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> <Details Bit_Position = "4" Name = "L_P03.S09ERQ" Type = "Non-Vital"/> </Card> <Card Id = "2" IP="92.168.1.2" Max_Bits = "32"> <Details/> <Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details> <Details Bit_Position = "2" Name = "L_S03E.S01FRQ" Type = "Vital"/> <Details Bit_Position = "3" Name = "L_S06E.S08FRQ" Type = "Vital"/> </Card> </CardInput> </Input> </CBI_CONFIGURATION>
The program outputs:
Opening "test.xml" bool xmlDataExtractor::parseXml() void xmlDataExtractor::readInput() void xmlDataExtractor::readCardInput() void xmlDataExtractor::readCard() Card:-> Id[ 1 ] Ip[ "192.168.10.2" ] maxBits[ 16 ] void xmlDataExtractor::readDetails() Details: bitPosition[ 1 ] Name[ "L_P03_04ENPB" ] Type[ "Non-Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 2 ] Name[ "L_S03E.S01FRQ" ] Type[ "Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 3 ] Name[ "L_S06E.S08FRQ" ] Type[ "Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 4 ] Name[ "L_P03.S09ERQ" ] Type[ "Non-Vital" ] "" void xmlDataExtractor::readCard() Card:-> Id[ 2 ] Ip[ "92.168.1.2" ] maxBits[ 32 ] void xmlDataExtractor::readDetails() Details: bitPosition[ 0 ] Name[ "" ] Type[ "" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 1 ] Name[ "L_P03_04ENPB" ] Type[ "Non-Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 2 ] Name[ "L_S03E.S01FRQ" ] Type[ "Vital" ] "" void xmlDataExtractor::readDetails() Details: bitPosition[ 3 ] Name[ "L_S06E.S08FRQ" ] Type[ "Vital" ] ""
That is, it has successfully read both Cards, all 8 Details records, all their attributes, and their body text (none actually present). I see no problem here.
@ChrisW67 Thanks Chris, please share the function code for xmlDataExtractor::readDetails() and xmlDataExtractor::readCard() from your end.
And one more thing , which version of QT , you are using?for clarification, My function implementation is
//Case 1: when details tag have attribute void xmlDataExtractor::readDetails() { qDebug() << Q_FUNC_INFO; Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"; }
//case 2: when details tag does not have attribute void xmlDataExtractor::readDetails() { qDebug() << Q_FUNC_INFO; Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QString text = xml.readElementText(); qDebug()<<text; }
-
@ChrisW67 Thanks Chris, please share the function code for xmlDataExtractor::readDetails() and xmlDataExtractor::readCard() from your end.
And one more thing , which version of QT , you are using?for clarification, My function implementation is
//Case 1: when details tag have attribute void xmlDataExtractor::readDetails() { qDebug() << Q_FUNC_INFO; Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"; }
//case 2: when details tag does not have attribute void xmlDataExtractor::readDetails() { qDebug() << Q_FUNC_INFO; Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QString text = xml.readElementText(); qDebug()<<text; }
@belcsns The code I am using is already posted in this thread. The readDetails() implementation is from your original post minus the unnecessary pre-processor directives and plus some debug output.
There is no difference in the processing path for elements with or without attributes.
This works with Qt 5.15.3 or Qt 6.5.2 on Linux, GCC 11.4
-
@belcsns The code I am using is already posted in this thread. The readDetails() implementation is from your original post minus the unnecessary pre-processor directives and plus some debug output.
There is no difference in the processing path for elements with or without attributes.
This works with Qt 5.15.3 or Qt 6.5.2 on Linux, GCC 11.4
@ChrisW67 Thanks Chris, actually I have put that preprocessor directive to bifurcate the read details implementation.
so if I understood you right than you are using following code
void xmlDataExtractor::readDetails() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"<<endl; QString text = xml.readElementText(); qDebug()<<text<<endl; }
As details tag is like
<Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details>
But I am using this part of code-
// details tag with attribute and no text data void xmlDataExtractor::readDetails() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"<<endl; }
i.e. without QString text = xml.readElementText(); as it it not needed. Request to remove this line from your code too. than you will find , it is not reading.
While fixing this , I have to include QString text = xml.readElementText(); in code, but why it is needed when detail tag does not have any text information.when detail tag is like - (with out attribute )
<Details>Text 1</Details> <Details>text2</Details>
than my implementation is
void xmlDataExtractor::readDetails() { QString text = xml.readElementText(); qDebug()<<text<<endl; }
in this case code works just fine.
So why in 1st case, without adding QString text = xml.readElementText(); code is not able to read detail tag with attribute.
I hope , now the issue will be clear to you.
Please once read again the thread, if problem is still not clear.
By the way, thank for your efforts and answers. -
@ChrisW67 Thanks Chris, actually I have put that preprocessor directive to bifurcate the read details implementation.
so if I understood you right than you are using following code
void xmlDataExtractor::readDetails() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"<<endl; QString text = xml.readElementText(); qDebug()<<text<<endl; }
As details tag is like
<Details Bit_Position = "1" Name = "L_P03_04ENPB" Type = "Non-Vital"></Details>
But I am using this part of code-
// details tag with attribute and no text data void xmlDataExtractor::readDetails() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("Details")); QXmlStreamAttributes attrs = xml.attributes(); int bitPosition = attrs.value(bitPositionAttribute()).toInt(); QString Name = attrs.value(nameAttribute()).toString(); QString Type = xml.attributes().value(typeAttribute()).toString(); qDebug()<<"Details: bitPosition["<<bitPosition<<"] Name["<<Name<<"] Type["<<Type<<"]"<<endl; }
i.e. without QString text = xml.readElementText(); as it it not needed. Request to remove this line from your code too. than you will find , it is not reading.
While fixing this , I have to include QString text = xml.readElementText(); in code, but why it is needed when detail tag does not have any text information.when detail tag is like - (with out attribute )
<Details>Text 1</Details> <Details>text2</Details>
than my implementation is
void xmlDataExtractor::readDetails() { QString text = xml.readElementText(); qDebug()<<text<<endl; }
in this case code works just fine.
So why in 1st case, without adding QString text = xml.readElementText(); code is not able to read detail tag with attribute.
I hope , now the issue will be clear to you.
Please once read again the thread, if problem is still not clear.
By the way, thank for your efforts and answers.@belcsns said in Query Regarding QXmlStreamReader API:
But I am using this part of code
I think everyone except you read your original post as, "if the data changes (i.e. removing attributes) the behaviour changes", not "if the code changes, the behaviour changes." The first is a run-time input issue, the second is self-evident.
Posting a small, self-contained program that demonstrates the problem is invaluable. Firstly, it often leads to discovering your own solution, and secondly it expresses the problem concretely. This caused confusion right from day one and prompted @SGaist's question about the conditional compilation.
Now that we know exactly what your code looks like...
If you do not call readElementText(), skipCurrentElement(), or otherwise process the content of the <Details> element to completion then the current element is <Details> when you exit this function and return to readCardInput(). You then call readNextStartElement(), which is documented thus (emphasis mine):
Reads until the next start element within the current element. Returns true when a start element was reached. When the end element was reached, or when an error occurred, false is returned.
So, readNextStartElement() consumes the remainder of the current <Details> element, returns false, and leaves the current element as </Details>. If the while loop did not terminate at that point, and you called readDetails() again I would expect the Q_ASSERT to fail.
@belcsns said in Query Regarding QXmlStreamReader API:
So question is
why xml.readNextStartElement() statement behaves differently in Details in xmlDataExtractor::readCard() function?readNextStartElement() is behaving as documented but its input has changed.
-
@belcsns said in Query Regarding QXmlStreamReader API:
But I am using this part of code
I think everyone except you read your original post as, "if the data changes (i.e. removing attributes) the behaviour changes", not "if the code changes, the behaviour changes." The first is a run-time input issue, the second is self-evident.
Posting a small, self-contained program that demonstrates the problem is invaluable. Firstly, it often leads to discovering your own solution, and secondly it expresses the problem concretely. This caused confusion right from day one and prompted @SGaist's question about the conditional compilation.
Now that we know exactly what your code looks like...
If you do not call readElementText(), skipCurrentElement(), or otherwise process the content of the <Details> element to completion then the current element is <Details> when you exit this function and return to readCardInput(). You then call readNextStartElement(), which is documented thus (emphasis mine):
Reads until the next start element within the current element. Returns true when a start element was reached. When the end element was reached, or when an error occurred, false is returned.
So, readNextStartElement() consumes the remainder of the current <Details> element, returns false, and leaves the current element as </Details>. If the while loop did not terminate at that point, and you called readDetails() again I would expect the Q_ASSERT to fail.
@belcsns said in Query Regarding QXmlStreamReader API:
So question is
why xml.readNextStartElement() statement behaves differently in Details in xmlDataExtractor::readCard() function?readNextStartElement() is behaving as documented but its input has changed.
-