Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Reading XML file



  • Hi all,

    In my application, I need to implement options to save, modify, remove xml files.
    I can save the data (getting information with a tab widget), as follows:

    void StageTwoNew::on_pushButton_clicked()
    {
    
        QString filename = ui->lineEdit_3->text();
        QString path = QCoreApplication::applicationDirPath()+"/data/"+filename+".xml";
        QFile file(path);
    
        if(!file.open(QFile::WriteOnly | QFile::Text))
        {
            qDebug () << "Error saving XML file...."; 
            file.close();
            return;
        }
    
        QDomDocument xml("dataentry");
    
        QDomElement root = xml.createElement("subject details");
        root.setAttribute("catagory","run session");
        xml.appendChild(root);
    
        QDomElement tagName = xml.createElement("Name");
        root.appendChild(tagName);
        QDomText textName = xml.createTextNode(ui->lineEdit->text());
        tagName.appendChild(textName);
    
        QDomElement tagSname = xml.createElement("Surname");
        root.appendChild(tagSname);
        QDomText textSname = xml.createTextNode(ui->lineEdit_2->text());
        tagSname.appendChild(textSname);
    
        QDomElement tagPID = xml.createElement("Subject ID");
        root.appendChild(tagPID);
        QDomText textPID = xml.createTextNode(ui->lineEdit_3->text());
        tagPID.appendChild(textPID);
    
        QDomElement tagDateTime = xml.createElement("Date");
        root.appendChild(tagDateTime);
        QDomText textDateTime = xml.createTextNode(ui->dateTimeEdit->text());
        tagDateTime.appendChild(textDateTime);
    
        QDomElement tagNote = xml.createElement("Extra Note");
        root.appendChild(tagNote);
        QDomText textNote = xml.createTextNode(ui->textEdit->toPlainText());
        tagNote.appendChild(textNote);
    
    
        QTextStream output(&file);
        output << xml.toString();
    
    
        file.close();
    
        
    }
    

    I now want to implement modify part. Basically I need to open the xml file and to present content to the same tab widget for user to modify and save it.

    I did this when clicked modify button in the form:

    void MainWindow::on_pushButton_2_clicked()
    {
         QDomDocument document;
    
             QString path = QCoreApplication::applicationDirPath()+"/data/";
    
             QString filename = QFileDialog::getOpenFileName(this, ("Open file"), path, "Xml files (*.xml)");
    
            // Open a file for reading
            QFile file(filename);
            if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
            {
    
                qDebug() << "Failed to open the file for reading.";
    
            }
    
            else
            {
                // loading
                if(!document.setContent(&file))
                {
               
                    qDebug() << "Failed to load the file for reading.";
    
                }
                file.close();
            }
    
            // Getting root element
            QDomElement root = document.firstChildElement();
    
            // retrievelements(QDomElement root, QString tag, QString att)
            retrievElements(root, "Dorm", "Name");
    
            qDebug() << "Reading finished";
    }
    

    Here the file is opened OK but I can't load the file for reading. What I'm doing wrong here?
    I need to load the content of xml file and present into the tab widget for the user to edit.

    Any suggestion will be helpful. Thanks in advance



  • @russjohn834
    I assume you mean it fails on document.setContent(&file)? So use the https://doc.qt.io/qt-5/qdomdocument.html#setContent-6 overload to obtain all the error information via the optional parameters?



  • @JonB Thank you. Could you please show me how to use optional parameters of setContent to get error information?


  • Lifetime Qt Champion

    @russjohn834 Please read documentation, this is nothing special:

    QString errorMsg;
    int errorLine;
    int errorColumn;
    if(!document.setContent(&file, &errorMessage, &errorLine, &errorColumn))
    


  • @russjohn834
    Well I'm not a C++-er, I thought you'd know from the doc page syntax, you're already managing to pass &file for QIODevice *dev.

    QDomDocument::setContent(QIODevice *dev, QString *errorMsg = nullptr, int *errorLine = nullptr, int *errorColumn = nullptr)
    

    so something like

    QFile file;
    QString errorMsg;
    int errorLine, errorColumn;
    if (!document.setContent(&file, &errorMsg, &errorLine, &errorColumn))
    {
        qDebug () << errorMsg << errorLine << errorColumn
    }
    

    and then look at your XML in that light.



  • Thank you @JonB, @jsulm

    I'm getting following error (AND error line and column) while loading the xml file:

    "unexpected character" 2 18

    I'm trying to read xml file, which looks like this:

    <!DOCTYPE detailsentry>
    <subject details catagory="run session">
     <Name>Rob</Name>
     <Surname>John</Surname>
     <Patient ID>PID12HL</Patient ID>
     <Date>06/11/2019 20:00</Date>
     <Clinician Note>Some notes to test this section</Clinician Note>
    </subject details>
    

    Any thoughts where I'm getting wrong!?



  • @russjohn834
    Yes, on line #2 at character #18! That's what the error info is telling you!

    <subject details catagory="run session">
    

    Count to character #18. What is that space in details catagory? (BTW, if you care, category is the correct spelling.) You can't have a space there. Nor for that matter in your <Patient ID> and others. Where did you get this XML from? You need to test your code with well-formed XML before you do anything.



  • Thank you @JonB !

    Now I can load the xml file:

    <!DOCTYPE detailsentry>
    <subject_details>
     <Name>Pete</Name>
     <Surname>Batty</Surname>
     <Patient_ID>GH34TRM</Patient_ID>
     <Date>06/11/2019 16:00</Date>
     <Clinician_Note>test note to display</Clinician_Note>
    </subject_details>
    

    I'm trying to parse data ( Name, Surname, Patient_ID, Date and Clinician_Note ) from this xml file.

     domDocument.setContent(&file);
     QDomElement topElement = domDocument.documentElement();
     QDomNode domNode = topElement.firstChild();
    
     while (!domNode.isNull())
     {
        QDomElement domElement = domNode.toElement();
         if (!domElement.isNull())
            {
             qDebug()<<"Tag name"<<topElement.tagName();
            }
      domNode = domNode.nextSibling();
     }
    
    

    This does output Tag name "subject_details" for 5 times. How can I parse content in each line?



  • @russjohn834 said in Reading XML file:

    qDebug()<<"Tag name"<<topElement.tagName();
    

    This does output Tag name "subject_details" for 5 times. How can I parse content in each line?

    Now come on :) Nicely, if it prints the same thing 5 times, look at what it's printing! topElement doesn't change in the loop, does it? But domElement does ...



  • This post is deleted!


  • @russjohn834
    I'm not going to answer every question, you have to do some work yourself! Did you try looking at the documentation for QDomElement since that is what you are asking about? Did you like the look of https://doc.qt.io/qt-5/qdomelement.html#text?



  • Thanks @JonB . Sorry I just found what I need. I can directly parse content of eachdomElement by following

    QDomElement topElement = domDocument.documentElement();
    topElement.elementsByTagName("Name").at(0).firstChild().nodeValue();
    topElement.elementsByTagName("Surname").at(0).firstChild().nodeValue(); ....
    


  • @russjohn834
    You can, but why change over to that way of doing it when you are already using QDomElement calls elsewhere which is more convenient?



  • I was too much confused about different terminologies of xml and methods of QDomDocument. I'm fiddling with my very basic knowledge to parse data from xml :) Yes, the documentation makes it more clear.

    @JonB said in Reading XML file:

    @russjohn834
    You can, but why change over to that way of doing it when you are already using QDomElement calls elsewhere which is more convenient?

    Did not get your point. You recommend topElement.elementsByTagName("Name").at(0).firstChild().nodeValue();
    than using loop to fetch content?



  • @russjohn834
    My thought/inclination is to make the reading code look like the code you already show, which uses QDomElement. So something like:

    QDomNode domElement = topElement.elementsByTagName("Name").at(0).firstChild();
    QDomElement domElement = domNode.toElement();
    if (!domElement.isNull())
        return domElement.text();
    

    It's just a matter of style. If I access things in one place via QDomElement calls, with its dedicated text() method, I prefer not to go via QDomNode and its nodeValue() method somewhere else. Just makes code easier to search/maintain/debug if you keep consistency where possible.



  • Thanks for your feedback @JonB , @jsulm


Log in to reply