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

QXmlStream and QTableWidget read and write xml file



  • I have a tableWidget :0_1536218468722_Scr.png

    I read the content with this code. I know it has problem

        QString mList ;
        for(int row = 0;row <ui->tableWidget->rowCount(); row++)
        {
    
            for(int column = 0;column< ui->tableWidget->columnCount() ;column++)
            {
                QTableWidgetItem *item1(ui->tableWidget->item(row,column));
                if(item1) {
    
                    qDebug() << ui->tableWidget->item(row,column)->text();
                   mList += ui->tableWidget->item(row,column)->text()+",";
                }
            }
            mList += "\n";
        }
        mList.remove(QRegExp("[\n]{2}"));
        qDebug() << mList;
    }
    

    How can i parse the data and populate in xml like this :

    <words>
     <row ID="0" text="row1">
      <col1 ID="0" text="item1"/>
      <col2 ID="1" text="item11"/>
     </row>
     </words>
    


  • QString result;
    QXmlStreamWriter writer(&result);
    writer.setAutoFormatting(true);
    writer.writeStartElement(QStringLiteral("words"));
    for(int i=0, maxRow = ui->tableWidget->rowCount();i<maxRow ;++i){
        writer.writeStartElement(QStringLiteral("row"));
        writer.writeAttribute(QStringLiteral("ID"),QString::number(i));
        // no idea where you take your text="row1" attribute from
        for(int j=0, maxCol = ui->tableWidget->columnCount();j<maxCol ;++j){
            writer.writeStartElement(QStringLiteral("col%1").arg(j+1));
            writer.writeAttribute(QStringLiteral("ID"),QString::number(j));
            writer.writeAttribute(QStringLiteral("text"),ui->tableWidget->model()->index(i,j).data().toString());
            writer..writeEndElement(); //col#
        }
        writer..writeEndElement(); //row
    }
    writer..writeEndElement(); //words
    qDebug() << result;
    


  • @behruz-montazeri
    The important thing to note in @VRonin's (correct) answer is that you do not first a build a string out of your table data and then parse it --- that would be madness! You produce the XML as you go along in the first place, where you already know the correct structure without having to parse anything.



  • @JonB
    Yes this way is very better.Thanks



  • @VRonin
    When i add data manually I don't know why it doesn't add last column.



  • @behruz-montazeri Can you show us your code?



  • Maybe there's a bug because items i added in Qtcreator gui are in the file but when i add another records last one is empty "" .

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDebug>
    #include <QtXml>
    
    #include <QTextStream>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
        ui->tableWidget->setColumnWidth(0,this->width()/2);
        ui->tableWidget->setColumnWidth(1,this->width()/2);
    }
    
    
    
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::on_action_Save_triggered()
    {
        QString result;
        QXmlStreamWriter writer(&result);
        writer.setAutoFormatting(true);
        writer.writeStartElement(QStringLiteral("words"));
        for(int i=0, maxRow = ui->tableWidget->rowCount();i<maxRow ;++i){
            writer.writeStartElement(QStringLiteral("row"));
            writer.writeAttribute(QStringLiteral("ID"),QString::number(i));
            for(int j=0, maxCol = ui->tableWidget->columnCount();j<maxCol ;++j){
                writer.writeStartElement(QStringLiteral("col%1").arg(j+1));
                writer.writeAttribute(QStringLiteral("ID"),QString::number(j));
                writer.writeAttribute(QStringLiteral("text"),ui->tableWidget->model()->index(i,j).data().toString());
                writer.writeEndElement(); //col
            }
            writer.writeEndElement(); //row
        }
        writer.writeEndElement(); //words
        qDebug() << result;
        QFile file("/home/behruz/Qt/TestPro/my.xml");
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            qDebug() << "Open the file for writing failed";
        }
        else
        {
            QTextStream stream(&file);
            stream << result;
            file.close();
            qDebug() << "Writing is done";
        }
    }
    


    1. QXmlStreamWriter can operate directly on a QIODevice (like QFile), no need to put a string in the middle and use QTextStream. Your code crates a big inconsistency with encodings if you use writeStartDocument
    2. when i add another records last one is empty

    How do you add them?



  • @VRonin

    When i run the program and add some record to QTableWidget the last one won't write to file.
    0_1536250415442_Scr.png

    <words>
        <row ID="0">
            <col1 ID="0" text="item 1"/>
            <col2 ID="1" text="item 11"/>
        </row>
        <row ID="1">
            <col1 ID="0" text="item 2 "/>
            <col2 ID="1" text="item 22"/>
        </row>
        <row ID="2">
            <col1 ID="0" text="item 3"/>
            <col2 ID="1" text="item 33"/>
        </row>
        <row ID="3">
            <col1 ID="0" text="a"/>
            <col2 ID="1" text="b"/>
        </row>
        <row ID="4">
            <col1 ID="0" text="c"/>
            <col2 ID="1" text="d"/>
        </row>
        <row ID="5">
            <col1 ID="0" text="e"/>
            <col2 ID="1" text=""/>
        </row>
    


  • I want the reverse functionality to read the file and add to QTableWidget i tried but i couln't :

        QFile file( "/home/behruz/Qt/TestPro/my.xml" );
        if( !file.open( QFile::ReadOnly | QFile::Text ) ) {
            // print error cannot open
        }
        QXmlStreamReader reader;
        reader.setDevice( &file );
        reader.readNext();
    
        if (reader.readNextStartElement()) {
            if (reader.name() == "words"){
                while(reader.readNextStartElement()){
                    if(reader.name() == "col1"){
                        QString s = reader.readElementText();
                        qDebug(qPrintable(s));
                    }
                }
            }
        }
    


  • @behruz-montazeri
    Compare your code here line for line against your code above for outputting the XML.

    writer.writeAttribute(QStringLiteral("text"),ui->tableWidget->model()->index(i,j).data().toString());
    

    shows you are storing text as an attribute (text="item1").

    That does not pair with your

    QString s = reader.readElementText();
    

    which will be the text inside each element, where you store nothing....



  •     QFile file("/home/behruz/Qt/TestPro/my.xml");
        if (file.open(QIODevice::ReadOnly)) {
            QXmlStreamReader reader(file.readAll());
            file.close();
            while(!reader.atEnd()) {
                reader.readNext();
                if (reader.isStartElement()) {
                    if (reader.name() == "words") {
                        reader.readNextStartElement();
                        if(reader.name() == "row"){
                            reader.readNextStartElement();
    
                            foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
                                if (attr.name().toString() == QLatin1String("text")) {
                                    QString attribute_value = attr.value().toString();
                                    qDebug(qPrintable(attribute_value));
                                }
                            }
                        }
                    }
                }
            }
        }
    

    It only shows the item 1 how populate it in QTableWidget ?



  • @behruz-montazeri
    Again, compare your reader against the writer code you have. That loops round every row, doesn't it? But your reader only has an if (reader.name() == "words"). Plus I don't see anything looping over the <col...> elements at all. And you say it only shows the first item (first row & column). Do you think that could be related to no loops?

    I'm not going to write it for you. You need to look up the docs and read the necessary elements in the necessary loops. You're headed in the right direction, just think about where your code needs to loop and read what to get back to what you had for the writing code.



  • @JonB
    What's the loop statement ? I know it needs a loop but i can't find where and how.



  • @behruz-montazeri
    Loop statements are for, while, foreach. The writer used fors because it knew how many rows & columns there were. You'll probably want whiles in the reader, certainly to move through all the <row> elements.



  • @JonB
    I already used a loop :

    foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
                            if (attr.name().toString() == QLatin1String("text")) {
                                stList.append( attr.value().toString());
                                qDebug() << stList;
                            }
    

    But it seems it only works for one record. Give me the code or a real hint. Thanks.



  • @behruz-montazeri said in QXmlStream and QTableWidget read and write xml file:

    QXmlStreamReader reader(file.readAll());

    ??? This makes no sense, it should be QXmlStreamReader reader(&file); I guess



  • I corrected reading by using two loops.

     QStringList stList;
    
        QFile file("/home/behruz/Desktop/Temp/QTableWidgetXml/my.xml");
        if( !file.open( QFile::ReadOnly | QFile::Text ) ) {
            // print error cannot open
        }
        QXmlStreamReader reader(&file);
    
        while(!reader.atEnd()) {
            reader.readNext();
            if (reader.isStartElement()) {
                reader.readNextStartElement();
                for(int i=0;i<ui->tableWidget->rowCount();i++){
                    if(reader.name() == "row"){
    
                        reader.readNextStartElement();
                        for(int i=0;i<2;i++){
                            //                        qDebug() << reader.name();
                            foreach(const QXmlStreamAttribute &attr, reader.attributes()) {
    
                                if (attr.name().toString() == QLatin1String("text")) {
    
                                    stList.append( attr.value().toString());
                                    qDebug() << stList;
                                }
    
    
                            }
                            reader.readNextStartElement();
                            reader.readNextStartElement();
                        }
                    }
                    reader.readNextStartElement();
                }
    
            }
        }
    
    
            for(int i=0, maxRow = ui->tableWidget->rowCount();i<maxRow ;++i){
                for(int j=0, maxCol = ui->tableWidget->columnCount();j<maxCol ;++j){
                    QTableWidgetItem *newItem = new QTableWidgetItem(tr("%1").arg( stList[L]));
                    qDebug() << stList[i];
                    ui->tableWidget->setItem(i, j, newItem);
                   L++;
                }
            }
    


  • maybe the XmlModelSerialiserPrivate::writeXmlElement and XmlModelSerialiserPrivate::readXmlElement methods from https://github.com/VSRonin/QtModelUtilities/blob/master/src/xmlmodelserialiser.cpp might help


Log in to reply