Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Query Regarding QXmlStreamReader API
Forum Updated to NodeBB v4.3 + New Features

Query Regarding QXmlStreamReader API

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 3 Posters 551 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    belcsns
    wrote on last edited by
    #1

    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.

    1 Reply Last reply
    0
    • B belcsns

      @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.

      C Offline
      C Offline
      ChrisW67
      wrote on last edited by
      #10

      @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.

      B 1 Reply Last reply
      2
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by SGaist
        #2

        Hi,

        Why are you using a pre-processor macro for what seems to be a condition that depends on the doucement you read ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        1
        • B Offline
          B Offline
          belcsns
          wrote on last edited by belcsns
          #3

          @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.

          C 1 Reply Last reply
          0
          • B belcsns

            @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.

            C Offline
            C Offline
            ChrisW67
            wrote on last edited by ChrisW67
            #4

            @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.

            B 1 Reply Last reply
            2
            • C ChrisW67

              @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.

              B Offline
              B Offline
              belcsns
              wrote on last edited by belcsns
              #5

              @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 section

              void xmlDataExtractor::readCard()
              {
                  //.....
                  while (xml.readNextStartElement()) // this condition
                  {
                       //...
                  }
              }
              

              Question is why this behavior?

              C 1 Reply Last reply
              0
              • B belcsns

                @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 section

                void xmlDataExtractor::readCard()
                {
                    //.....
                    while (xml.readNextStartElement()) // this condition
                    {
                         //...
                    }
                }
                

                Question is why this behavior?

                C Offline
                C Offline
                ChrisW67
                wrote on last edited by
                #6

                @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.

                B 1 Reply Last reply
                0
                • C ChrisW67

                  @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.

                  B Offline
                  B Offline
                  belcsns
                  wrote on last edited by belcsns
                  #7

                  @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;
                  }
                  
                  C 1 Reply Last reply
                  0
                  • B belcsns

                    @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;
                    }
                    
                    C Offline
                    C Offline
                    ChrisW67
                    wrote on last edited by
                    #8

                    @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

                    B 1 Reply Last reply
                    1
                    • C ChrisW67

                      @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

                      B Offline
                      B Offline
                      belcsns
                      wrote on last edited by belcsns
                      #9

                      @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.

                      C 1 Reply Last reply
                      0
                      • B belcsns

                        @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.

                        C Offline
                        C Offline
                        ChrisW67
                        wrote on last edited by
                        #10

                        @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.

                        B 1 Reply Last reply
                        2
                        • C ChrisW67

                          @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.

                          B Offline
                          B Offline
                          belcsns
                          wrote on last edited by
                          #11

                          @ChrisW67 Thanks Chris, this was the first time , I have posted a question on any forum. So because of this ,may be linguistic issue was there. I tried to put the my query as expressive as I can.

                          Once again, Thanks Chris.

                          1 Reply Last reply
                          0
                          • B belcsns has marked this topic as solved on

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved