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. Modify an XML file with QDomDocument
Forum Updated to NodeBB v4.3 + New Features

Modify an XML file with QDomDocument

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 3 Posters 633 Views
  • 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.
  • C Offline
    C Offline
    Ceng0
    wrote on last edited by Ceng0
    #1

    Hi,

    I am modifying an XML file using QDomDocument.

    • When I want to update the xml file, it adds the xmlns attribute to each tag.

    • I have tried to remove the xmlns tag by navigating through each tag, but it cannot remove it because it cannot find the xmlns tag in the items.

    • QDomElement works as if there is no xmlns tag in the generatorElement content, but when I want to write to the file, it adds the xmlns tag. How can I fix it?

    Xml file:

    <?xml version="1.0" encoding="UTF-8"?>
    <entity xmlns="http://www.sample.com.tr/EntityConfSchema" xmlns:attr="http://www.sample.com.tr/AttributeTypes" xmlns:sim="http://www.sample.com.tr/DataTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
       <sample-info>
       	<sample-type>1111111</sample-type>
       </sample-info>
       <sample-initials>
       	<attribute-nvp name="sampleName">
       		<attribute xsi:type="attr:StringAttribute" value="sampleValue"/>
       	</attribute-nvp>
       	<attribute-nvp name="sampleName">
       		<attribute xsi:type="attr:StringAttribute" value="sampleValue"/>
       	</attribute-nvp>
       	<attribute-nvp name="sampleName">
       		<attribute xsi:type="attr:StringAttribute" value="sampleValue"/>
       	</attribute-nvp>
       </sample-initials>
    </entity>
    

    Here's my code:

    void SampleWidget::on_pushButtonSave_clicked()
    {
        QString entityCurrentFile = "sampleFile.entity";
        QString fileToCopy = "fileToCopy.entity";
    
        if (QFile::exists(entityCurrentFile))
        {
            QFile::remove(entityCurrentFile);
        }
    
        QFile::copy(fileToCopy , entityCurrentFile);
    
        QFile file(entityCurrentFile);
        if (!file.open(QIODevice::ReadWrite | QIODevice::Text))
        {
            SIM_LOG_ERROR("CANNOT OPEN");
            return;
        }
    
        QDomDocument* generatorDocument = new QDomDocument;
        if (!generatorDocument->setContent(&file, true))
        {
            return;
        }
    
        file.close();
    
    //checked the xmlData , it appears to be corrupted. There is xmlns attribute in every tag
        QByteArray xmlData = generatorDocument->toByteArray();
    
    
        QDomElement generatorElement = generatorDocument->documentElement();
    
        removeXmlnsAttributesFromDocument(generatorElement);
    
        modifyEntityFile(generatorElement);   // modify 
    
        QFile outputFile(entityCurrentFile);
        // Save content back to the file
        if (!outputFile.open(QIODevice::Truncate | QIODevice::WriteOnly)) {
            return;
        }
        QTextStream stream(&outputFile);
        stream << generatorDocument->toByteArray();
        QByteArray xmlData = generatorDocument->toByteArray();
        outputFile.close();
    }
    
    void SampleWidget::removeXmlnsAttributesFromDocument(QDomNode& node)
    {
        QDomNodeList children = node.childNodes();
    
        for (int i = 0; i < children.size(); ++i) {
            QDomNode childNode = children.at(i);
    
            if (childNode.isElement()) {
                QDomElement element = childNode.toElement();
                QString attributeName = "xmlns";
    
                if (element.hasAttribute(attributeName)) {
                    element.removeAttribute(attributeName);
                    qDebug() << "Attribute" << attributeName << "removed from node" << attributeName;
                }
                else {
                    qDebug() << "Node" << attributeName << "does not have attribute" << attributeName;
                }
            }
    
            removeXmlnsAttributesFromDocument(childNode);
        }
    }
    

    Result:

    <?xml version="1.0" encoding="UTF-8"?>
    <entity xmlns="http://www.sample.com.tr/EntityConfSchema">
    	<sample-info xmlns="http://www.sample.com.tr/EntityConfSchema">
    		<sample-type xmlns="http://www.sample.com.tr/EntityConfSchema">111111</sample-type>
    	</sample-info>
    	<sample-initials xmlns="http://www.sample.com.tr/EntityConfSchema">
    		<attribute-nvp xmlns="http://www.sample.com.tr/EntityConfSchema" name="ExampleName">
    			<attribute xmlns="http://www.sample.com.tr/EntityConfSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:type="attr:StringAttribute" value="ExampleValue"/>
    		</attribute-nvp>
    		<attribute-nvp xmlns="http://www.sample.com.tr/EntityConfSchema"  name="ExampleName">
    			<attribute xmlns="http://www.sample.com.tr/EntityConfSchema"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="attr:StringAttribute" value="ExampleValue"/>
    		</attribute-nvp>
    		<attribute-nvp xmlns="http://www.sample.com.tr/EntityConfSchema"  name="ExampleName">
    			<attribute xmlns="http://www.sample.com.tr/EntityConfSchema"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="attr:StringAttribute" value="ExampleValue"/>
    		</attribute-nvp>
    	</sample-initials>
    </entity>
    

    Expected xml file:

    <?xml version="1.0" encoding="UTF-8"?>
    <entity xmlns="http://www.sample.com.tr/EntityConfSchema" xmlns:attr="http://www.sample.com.tr/AttributeTypes" xmlns:sim="http://www.sample.com.tr/DataTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    	<sample-info>
    		<sample-type>88888888</sample-type>
    	</sample-info>
    	<sample-initials>
    		<attribute-nvp name="ExampleName">
    			<attribute xsi:type="attr:StringAttribute" value="ExampleValue"/>
    		</attribute-nvp>
    		<attribute-nvp name="ExampleName">
    			<attribute xsi:type="attr:StringAttribute" value="ExampleValue"/>
    		</attribute-nvp>
    		<attribute-nvp name="ExampleName">
    			<attribute xsi:type="attr:StringAttribute" value="ExampleValue"/>
    		</attribute-nvp>
    	</sample-initials>
    </entity>
    
    JonBJ C 2 Replies Last reply
    0
    • C Ceng0

      Hi,

      I am modifying an XML file using QDomDocument.

      • When I want to update the xml file, it adds the xmlns attribute to each tag.

      • I have tried to remove the xmlns tag by navigating through each tag, but it cannot remove it because it cannot find the xmlns tag in the items.

      • QDomElement works as if there is no xmlns tag in the generatorElement content, but when I want to write to the file, it adds the xmlns tag. How can I fix it?

      Xml file:

      <?xml version="1.0" encoding="UTF-8"?>
      <entity xmlns="http://www.sample.com.tr/EntityConfSchema" xmlns:attr="http://www.sample.com.tr/AttributeTypes" xmlns:sim="http://www.sample.com.tr/DataTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
         <sample-info>
         	<sample-type>1111111</sample-type>
         </sample-info>
         <sample-initials>
         	<attribute-nvp name="sampleName">
         		<attribute xsi:type="attr:StringAttribute" value="sampleValue"/>
         	</attribute-nvp>
         	<attribute-nvp name="sampleName">
         		<attribute xsi:type="attr:StringAttribute" value="sampleValue"/>
         	</attribute-nvp>
         	<attribute-nvp name="sampleName">
         		<attribute xsi:type="attr:StringAttribute" value="sampleValue"/>
         	</attribute-nvp>
         </sample-initials>
      </entity>
      

      Here's my code:

      void SampleWidget::on_pushButtonSave_clicked()
      {
          QString entityCurrentFile = "sampleFile.entity";
          QString fileToCopy = "fileToCopy.entity";
      
          if (QFile::exists(entityCurrentFile))
          {
              QFile::remove(entityCurrentFile);
          }
      
          QFile::copy(fileToCopy , entityCurrentFile);
      
          QFile file(entityCurrentFile);
          if (!file.open(QIODevice::ReadWrite | QIODevice::Text))
          {
              SIM_LOG_ERROR("CANNOT OPEN");
              return;
          }
      
          QDomDocument* generatorDocument = new QDomDocument;
          if (!generatorDocument->setContent(&file, true))
          {
              return;
          }
      
          file.close();
      
      //checked the xmlData , it appears to be corrupted. There is xmlns attribute in every tag
          QByteArray xmlData = generatorDocument->toByteArray();
      
      
          QDomElement generatorElement = generatorDocument->documentElement();
      
          removeXmlnsAttributesFromDocument(generatorElement);
      
          modifyEntityFile(generatorElement);   // modify 
      
          QFile outputFile(entityCurrentFile);
          // Save content back to the file
          if (!outputFile.open(QIODevice::Truncate | QIODevice::WriteOnly)) {
              return;
          }
          QTextStream stream(&outputFile);
          stream << generatorDocument->toByteArray();
          QByteArray xmlData = generatorDocument->toByteArray();
          outputFile.close();
      }
      
      void SampleWidget::removeXmlnsAttributesFromDocument(QDomNode& node)
      {
          QDomNodeList children = node.childNodes();
      
          for (int i = 0; i < children.size(); ++i) {
              QDomNode childNode = children.at(i);
      
              if (childNode.isElement()) {
                  QDomElement element = childNode.toElement();
                  QString attributeName = "xmlns";
      
                  if (element.hasAttribute(attributeName)) {
                      element.removeAttribute(attributeName);
                      qDebug() << "Attribute" << attributeName << "removed from node" << attributeName;
                  }
                  else {
                      qDebug() << "Node" << attributeName << "does not have attribute" << attributeName;
                  }
              }
      
              removeXmlnsAttributesFromDocument(childNode);
          }
      }
      

      Result:

      <?xml version="1.0" encoding="UTF-8"?>
      <entity xmlns="http://www.sample.com.tr/EntityConfSchema">
      	<sample-info xmlns="http://www.sample.com.tr/EntityConfSchema">
      		<sample-type xmlns="http://www.sample.com.tr/EntityConfSchema">111111</sample-type>
      	</sample-info>
      	<sample-initials xmlns="http://www.sample.com.tr/EntityConfSchema">
      		<attribute-nvp xmlns="http://www.sample.com.tr/EntityConfSchema" name="ExampleName">
      			<attribute xmlns="http://www.sample.com.tr/EntityConfSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:type="attr:StringAttribute" value="ExampleValue"/>
      		</attribute-nvp>
      		<attribute-nvp xmlns="http://www.sample.com.tr/EntityConfSchema"  name="ExampleName">
      			<attribute xmlns="http://www.sample.com.tr/EntityConfSchema"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="attr:StringAttribute" value="ExampleValue"/>
      		</attribute-nvp>
      		<attribute-nvp xmlns="http://www.sample.com.tr/EntityConfSchema"  name="ExampleName">
      			<attribute xmlns="http://www.sample.com.tr/EntityConfSchema"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="attr:StringAttribute" value="ExampleValue"/>
      		</attribute-nvp>
      	</sample-initials>
      </entity>
      

      Expected xml file:

      <?xml version="1.0" encoding="UTF-8"?>
      <entity xmlns="http://www.sample.com.tr/EntityConfSchema" xmlns:attr="http://www.sample.com.tr/AttributeTypes" xmlns:sim="http://www.sample.com.tr/DataTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      	<sample-info>
      		<sample-type>88888888</sample-type>
      	</sample-info>
      	<sample-initials>
      		<attribute-nvp name="ExampleName">
      			<attribute xsi:type="attr:StringAttribute" value="ExampleValue"/>
      		</attribute-nvp>
      		<attribute-nvp name="ExampleName">
      			<attribute xsi:type="attr:StringAttribute" value="ExampleValue"/>
      		</attribute-nvp>
      		<attribute-nvp name="ExampleName">
      			<attribute xsi:type="attr:StringAttribute" value="ExampleValue"/>
      		</attribute-nvp>
      	</sample-initials>
      </entity>
      
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @Ceng0
      I have had a look at this.

      The text it saves may not be what you or I, as humans, would like, but it is still "correct".

      It chooses to repeat the namespace attributes on each element. I believe this is deliberate/hard-coded, so that it is always right. I came across somewhere (e.g. https://codebrowser.dev/qt5/qtbase/src/xml/dom/qdom.cpp.html#_ZNK15QDomAttrPrivate4saveER11QTextStreamii):

           * QDomElementPrivate::save() output a namespace declaration if
           * the element is in a namespace, no matter what
      

      What it is not doing is taking into account default namespace, which we would like it to do. I have not found any handling for this or way of forcing it. I agree there is some special handling where we cannot see these as attribute nodes after reading.

      If you passed false instead of true to setContent() you would get the original document content back as-was. You would also see the original attributes retained. I do not know if you can work with that --- depends what you are doing with/to the document --- but that is the simplest and may be only way.

      You might alternatively do your own writing via QXmlStreamWriter to get control over this, but I think that's quite a bit work and seems silly if you have a QDomDocument.

      1 Reply Last reply
      1
      • C Ceng0

        Hi,

        I am modifying an XML file using QDomDocument.

        • When I want to update the xml file, it adds the xmlns attribute to each tag.

        • I have tried to remove the xmlns tag by navigating through each tag, but it cannot remove it because it cannot find the xmlns tag in the items.

        • QDomElement works as if there is no xmlns tag in the generatorElement content, but when I want to write to the file, it adds the xmlns tag. How can I fix it?

        Xml file:

        <?xml version="1.0" encoding="UTF-8"?>
        <entity xmlns="http://www.sample.com.tr/EntityConfSchema" xmlns:attr="http://www.sample.com.tr/AttributeTypes" xmlns:sim="http://www.sample.com.tr/DataTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <sample-info>
           	<sample-type>1111111</sample-type>
           </sample-info>
           <sample-initials>
           	<attribute-nvp name="sampleName">
           		<attribute xsi:type="attr:StringAttribute" value="sampleValue"/>
           	</attribute-nvp>
           	<attribute-nvp name="sampleName">
           		<attribute xsi:type="attr:StringAttribute" value="sampleValue"/>
           	</attribute-nvp>
           	<attribute-nvp name="sampleName">
           		<attribute xsi:type="attr:StringAttribute" value="sampleValue"/>
           	</attribute-nvp>
           </sample-initials>
        </entity>
        

        Here's my code:

        void SampleWidget::on_pushButtonSave_clicked()
        {
            QString entityCurrentFile = "sampleFile.entity";
            QString fileToCopy = "fileToCopy.entity";
        
            if (QFile::exists(entityCurrentFile))
            {
                QFile::remove(entityCurrentFile);
            }
        
            QFile::copy(fileToCopy , entityCurrentFile);
        
            QFile file(entityCurrentFile);
            if (!file.open(QIODevice::ReadWrite | QIODevice::Text))
            {
                SIM_LOG_ERROR("CANNOT OPEN");
                return;
            }
        
            QDomDocument* generatorDocument = new QDomDocument;
            if (!generatorDocument->setContent(&file, true))
            {
                return;
            }
        
            file.close();
        
        //checked the xmlData , it appears to be corrupted. There is xmlns attribute in every tag
            QByteArray xmlData = generatorDocument->toByteArray();
        
        
            QDomElement generatorElement = generatorDocument->documentElement();
        
            removeXmlnsAttributesFromDocument(generatorElement);
        
            modifyEntityFile(generatorElement);   // modify 
        
            QFile outputFile(entityCurrentFile);
            // Save content back to the file
            if (!outputFile.open(QIODevice::Truncate | QIODevice::WriteOnly)) {
                return;
            }
            QTextStream stream(&outputFile);
            stream << generatorDocument->toByteArray();
            QByteArray xmlData = generatorDocument->toByteArray();
            outputFile.close();
        }
        
        void SampleWidget::removeXmlnsAttributesFromDocument(QDomNode& node)
        {
            QDomNodeList children = node.childNodes();
        
            for (int i = 0; i < children.size(); ++i) {
                QDomNode childNode = children.at(i);
        
                if (childNode.isElement()) {
                    QDomElement element = childNode.toElement();
                    QString attributeName = "xmlns";
        
                    if (element.hasAttribute(attributeName)) {
                        element.removeAttribute(attributeName);
                        qDebug() << "Attribute" << attributeName << "removed from node" << attributeName;
                    }
                    else {
                        qDebug() << "Node" << attributeName << "does not have attribute" << attributeName;
                    }
                }
        
                removeXmlnsAttributesFromDocument(childNode);
            }
        }
        

        Result:

        <?xml version="1.0" encoding="UTF-8"?>
        <entity xmlns="http://www.sample.com.tr/EntityConfSchema">
        	<sample-info xmlns="http://www.sample.com.tr/EntityConfSchema">
        		<sample-type xmlns="http://www.sample.com.tr/EntityConfSchema">111111</sample-type>
        	</sample-info>
        	<sample-initials xmlns="http://www.sample.com.tr/EntityConfSchema">
        		<attribute-nvp xmlns="http://www.sample.com.tr/EntityConfSchema" name="ExampleName">
        			<attribute xmlns="http://www.sample.com.tr/EntityConfSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:type="attr:StringAttribute" value="ExampleValue"/>
        		</attribute-nvp>
        		<attribute-nvp xmlns="http://www.sample.com.tr/EntityConfSchema"  name="ExampleName">
        			<attribute xmlns="http://www.sample.com.tr/EntityConfSchema"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="attr:StringAttribute" value="ExampleValue"/>
        		</attribute-nvp>
        		<attribute-nvp xmlns="http://www.sample.com.tr/EntityConfSchema"  name="ExampleName">
        			<attribute xmlns="http://www.sample.com.tr/EntityConfSchema"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="attr:StringAttribute" value="ExampleValue"/>
        		</attribute-nvp>
        	</sample-initials>
        </entity>
        

        Expected xml file:

        <?xml version="1.0" encoding="UTF-8"?>
        <entity xmlns="http://www.sample.com.tr/EntityConfSchema" xmlns:attr="http://www.sample.com.tr/AttributeTypes" xmlns:sim="http://www.sample.com.tr/DataTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        	<sample-info>
        		<sample-type>88888888</sample-type>
        	</sample-info>
        	<sample-initials>
        		<attribute-nvp name="ExampleName">
        			<attribute xsi:type="attr:StringAttribute" value="ExampleValue"/>
        		</attribute-nvp>
        		<attribute-nvp name="ExampleName">
        			<attribute xsi:type="attr:StringAttribute" value="ExampleValue"/>
        		</attribute-nvp>
        		<attribute-nvp name="ExampleName">
        			<attribute xsi:type="attr:StringAttribute" value="ExampleValue"/>
        		</attribute-nvp>
        	</sample-initials>
        </entity>
        
        C Offline
        C Offline
        ChrisW67
        wrote on last edited by ChrisW67
        #3

        @Ceng0
        I assume that you are using Qt 5 because in Qt 6 the second argument to QDomDocument::setContent() is not a bool.

        Depending on your actual requirements you may be able to achieve the desired result without turning on namespace handling. This, for example, modifies the document but does not add namespace attribute everywhere:

        #include <QCoreApplication>
        #include <QDomDocument>
        #include <QFile>
        
        int main(int argc, char** argv) {
                QCoreApplication app(argc, argv);
        
                QFile file("input.xml");
                if (file.open(QIODevice::ReadOnly)) {
                        QDomDocument doc;
                        doc.setContent(&file, false);
        
                        QDomElement docElem = doc.documentElement();
                        QDomElement first = docElem.firstChildElement("sample-initials");
                        first.setAttribute("xyzzy", "plugh");
        
                        QFile out("output.xml");
                        if (out.open(QIODevice::WriteOnly)) {
                                out.write(doc.toByteArray(2));
                        }
                }
        
                return 0;
        }
        

        Edit: Oops, just noticed that JonB already suggested this

        JonBJ 1 Reply Last reply
        0
        • C ChrisW67

          @Ceng0
          I assume that you are using Qt 5 because in Qt 6 the second argument to QDomDocument::setContent() is not a bool.

          Depending on your actual requirements you may be able to achieve the desired result without turning on namespace handling. This, for example, modifies the document but does not add namespace attribute everywhere:

          #include <QCoreApplication>
          #include <QDomDocument>
          #include <QFile>
          
          int main(int argc, char** argv) {
                  QCoreApplication app(argc, argv);
          
                  QFile file("input.xml");
                  if (file.open(QIODevice::ReadOnly)) {
                          QDomDocument doc;
                          doc.setContent(&file, false);
          
                          QDomElement docElem = doc.documentElement();
                          QDomElement first = docElem.firstChildElement("sample-initials");
                          first.setAttribute("xyzzy", "plugh");
          
                          QFile out("output.xml");
                          if (out.open(QIODevice::WriteOnly)) {
                                  out.write(doc.toByteArray(2));
                          }
                  }
          
                  return 0;
          }
          

          Edit: Oops, just noticed that JonB already suggested this

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @ChrisW67 said in Modify an XML file with QDomDocument:

          doc.setContent(&file, false);

          Yes, that is the false for "namespace processing" I was suggesting, which would be by far the simplest. Then everything stays like it is.

          But it depends on what the OP wants to do with the document read in (e.g. searching it?), if there are other namespaces involved, if they want to insert new nodes, etc.

          C 1 Reply Last reply
          0
          • JonBJ JonB

            @ChrisW67 said in Modify an XML file with QDomDocument:

            doc.setContent(&file, false);

            Yes, that is the false for "namespace processing" I was suggesting, which would be by far the simplest. Then everything stays like it is.

            But it depends on what the OP wants to do with the document read in (e.g. searching it?), if there are other namespaces involved, if they want to insert new nodes, etc.

            C Offline
            C Offline
            Ceng0
            wrote on last edited by
            #5

            @JonB Sorry for the late reply

            doc.setContent(&file, false); works for me. Thank you .

            1 Reply Last reply
            0
            • C Ceng0 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