Store the QDocument attributes in an ordered way



  • I am using the following function to write the content from a QDomDocument into a file.

    int MyClass::writeFile(const QString outfile,const QDomDocument* XMLContent)
    {
        QFile out(outfile);
        if (out.open(QIODevice::ReadWrite|QIODevice::Truncate))
        {
            LOG(INFO) << "Write Out File: " << outfile.toStdString();
            QTextStream stream( &out );
            QString Result_string;
            int ident = 3;
            Result_string = XMLContent->toString(ident);
            stream << Result_string << endl;
            out.close();
            return -1;
        }
        else
        {
            LOG(ERROR) << "ERROR - Cannot write file: " << outfile.toStdString();
            return 0;
        }
    }
    

    I am observing that the produced file does not always have the arguments put in the same order within a node.

    F.e. sometimes it might be:

    <myObject Attribute1="111" Attribute2="222" Attribute3="333">
    ...
    </myObject>
    

    and sometimes it might be:

    <myObject Attribute3="333" Attribute1="111" Attribute2="222">
    ...
    </myObject>
    

    I understand that this has no consequence on the generated XML - However it would be convenient if the attributes would always be stored in the same order so that I would able to easily diff two consecutively generated files.



  • Hi @Lolo67

    There is an old bug report which shows a workaround: https://bugreports.qt.io/browse/QTBUG-8158

    -Michael.



  • Make use of QStreamWriter instead, that solved this issue for me!

    QDomElement element = getUserDomElement();
    
    QByteArray byte_array;
    QXmlStreamWriter stream(&byte_array);
    
    stream.writeStartDocument();
    
    //(Recursive part)
    stream.writeStartElement(element.tagName());
    
    QVector<QString> attribute_names;
    const QDomNamedNodeMap attributes = element.attributes();
    for(quint32 i = 0; i < attributes.length(); ++i) {
      attribute_names << attributes.item(i).toAttr().name();
    }
    
    std::stable_sort(attribute_names.begin(), attribute_names.end());
    
    foreach(QString attr_name, attribute_names) {
      QDomAttr attr = attributes.namedItem(attr_name).toAttr();
      stream.writeAttribute(attr.name(), attr.value());
    }
    
    //If has children call recursive function...
    
    stream.writeEndElement();
    //(End recursive part)
    
    stream.writeEndDocument();
    
    QFile file("ordered_attributes.xml");
    if(file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
      file.write(byte_array);
      file.flush();
      file.close();
    }
    

    This will write one QDomElement on format:

    <tag a="value_a" b="value_b" ...></tag>
    

    where attributes are ordered by choice of sorting algorithm.

    If QDomElement has children this procedure can be called recursively with stream as argument.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.