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

Append new nodes to XML and resave



  • Hello Guys,

    I am relatively new to the Qt platform and hence I have stumbled upon, what I assume is a very basic problem and I am missing out on something.

    Task :: I want to add a new XML node to a particular child of an already saved XML document.

    What I have done :: I open the XML document, read all, close the file and make changes to the document in the memory and resave it.

    Problem :: I am not able to append the XML node to the correct child.

    void xml_general_data(int file_id, int id, int intksk, QString Operator, QString Group, QString Status, QDateTime timestamp){
            //document.clear();
            QDomElement device_name = document.createElement("device");
            device_name.setAttribute("name",QHostInfo::localHostName());
            document.appendChild(device_name);
            job_name = document.createElement("job");
            job_name.setAttribute("name","working result");
            job_name.setAttribute("id",QString::number(id));
            device_name.appendChild(job_name);
            QDomElement ksk_name = document.createElement("intksk");
            job_name.appendChild(ksk_name);
            ksk_name.appendChild(document.createTextNode(QString::number(intksk)));
            QDomElement operator_name = document.createElement("operator");
            job_name.appendChild(operator_name);
            operator_name.appendChild(document.createTextNode(Operator));
            QDomElement group_name = document.createElement("group");
            job_name.appendChild(group_name);
            group_name.appendChild(document.createTextNode(Group));
            test_result = document.createElement("testresult");
            test_result.setAttribute("status",Status);
            test_result.setAttribute("timestamp",timestamp.toString("dd.MM.yyyy hh:mm:ss"));
            job_name.appendChild(test_result);
    
            xml_path=QDir(absolute_path).filePath(file_name.section(".",0,0)+ QString::number(file_id)+".xml");
            QFile file(xml_path);
            if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
            {
                qDebug()<<"Failure";
    
            }
            else
            {
                QTextStream stream(&file);
                stream<<document.toString();
                file.close();
                qDebug()<<"Finished xml_general_data_"+ QString::number(file_id);
            }
        }
    
    
        void xml_header(int file_id, QString Operator){
            document.clear();
    
    
            xml_path=QDir(absolute_path).filePath(file_name.section(".",0,0)+QString::number(file_id)+".xml");
            QFile file(xml_path);
            file.open(QFile::ReadOnly |  QIODevice::Text);
            QDomDocument document;
            document.setContent(&file);
    
            QDomElement root=document.documentElement();
            file.close();
    
            qDebug()<<"Hello "+root.text();
    
            QDomElement header =document.createElement("header");
            //What to add here???
    
            root.appendChild(header);
            QDomElement operator_name_1 = document.createElement("operator");
            header.appendChild(operator_name_1);
            operator_name_1.appendChild(document.createTextNode(Operator));
    

    My result looks like this:
    939acd73-8f51-45d3-b1c3-2454611fa790-image.png

    But should be looking like this:
    61e3c051-e965-4d1e-911f-97f54653b72a-image.png

    I've been stuck at it for 2 days now and so any suggestion of what I could do would be of great relief.

    Thanks in advance. :)



  • @sibha said in Append new nodes to XML and resave:

        QDomElement root=document.documentElement();
    
        QDomElement header =document.createElement("header");
        //What to add here???
    
        root.appendChild(header);
    

    Since you append it to root it comes out in <device> after </job> as you show. If you want it to come inside <testresult> then that's what you must append <header> to.



  • @JonB

    That's exactly what I was doing at the beginning but then I don't get <header> appended at all.

    1c871f88-23e7-4748-9aa8-d65973cd26ba-image.png

    2462c559-284b-4f31-a606-45091f0fe1e3-image.png

    Guess, I am really cooking up something really bad here.



  • For the simple XML structure you have, find the element you want to append the child to with elementsByTagName(). For example:

    #include <QCoreApplication>
    #include <QDomDocument>
    #include <QFile>
    #include <QDebug>
    
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QFile file("/tmp/test/test.xml");
        if (file.open(QFile::ReadOnly |  QIODevice::Text)) {
            qDebug() << "Opened input file";
            QDomDocument document;
            if (document.setContent(&file)) {
                qDebug() << "Loaded input file";
                QDomElement root=document.documentElement();
    
                // Find the testresult node(s)
                QDomNodeList nodes = document.elementsByTagName("testresult");
    
                if (nodes.count() == 1) {
                    qDebug() << "Found testresult";
                    QDomElement header =document.createElement("header");
                    nodes.at(0).appendChild(header);
                }
    
    #if 0
                // If there might be more than one testresult then
                for(int i = 0; i < nodes.count(); ++i) {
                  qDebug() << "Found testresult";
                  QDomElement header = document.createElement("header");
                  nodes.at(i).appendChild(header);
                }
    #endif 
            }
            // Save result here
            QFile out("/tmp/test/test_out.xml");
            if (out.open(QFile::WriteOnly | QIODevice::Text)) {
                QTextStream stream( &out );
                stream << document.toString();
                out.close();
            }
        }
        file.close();
    
        return 0;
    }
    

    Input:

    <?xml version="1.0" ?>
    <device name="foo">
            <job name="bar">
                    <testresult status="io"/>
            </job>
    </device>
    

    Output:

    <?xml version='1.0'?>
    <device name="foo">
     <job name="bar">
      <testresult status="io">
       <header/>
      </testresult>
     </job>
    </device>
    


  • @sibha said in Append new nodes to XML and resave:

    That's exactly what I was doing at the beginning but then I don't get <header> appended at all.

    I don't know what you were doing but appending to the <testresult> node is what you need to do.

    I want to add a new XML node to a particular child of an already saved XML document.
    and make changes to the document in the memory and resave it.

    If you are saying you have already read in an existing XML document, then you do not create a new node for, say, <testresult> if it is already there. You must find the existing <testresult> node in the document and append to that. I am not sure how your existing code is broken into what you create first time for the document versus what you do in the way of finding what is already in an existing document which has been read. You do not seem to be searching for any existing nodes. I think this is what @ChrisW67 is showing you.



  • @ChrisW67 @JonB

    I even tried searching for the node but I was missing

    nodes.at(0).appendChild(header);
    

    But it solves my problem now. Thank you both for your help, I much appreciate it.


Log in to reply