How to remove a nested tag from XML doc using QDomDocument

1k Views Asked by At

I need to remove a nested multilevel (unknown depth) tag from a XML file using QDomDocument. What is the proper way of doing this? Here is a sample of XML file

<A>
  <B>
    <C>
      .............................
    </C>
  </B>
</A>
1

There are 1 best solutions below

3
On

I would not even use QDomDocument, aka. QtXml for this as the stream reader and writer classes are relatively simple to use in QtCore. Here goes my solution that could be further extended to support other things, too:

QtCore

testin.xml

<A>
  <B>
    <C>
      .............................
    </C>
  </B>
</A>

testout.xml

<?xml version="1.0" encoding="UTF-8"?>
<A>
    <B/>
</A>

main.cpp

#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
#include <QString>
#include <QFile>

int main()
{
    QFile inputFile("testin.xml");
    if (!inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "File open error:" << inputFile.errorString();
        return 1;
    }
    QFile outputFile("testout.xml");
    if (!outputFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qDebug() << "File open error:" << outputFile.errorString();
        return 1;
    }
    QXmlStreamReader inputStream(&inputFile);
    QXmlStreamWriter outputStream(&outputFile);
    outputStream.setAutoFormatting(true);
    outputStream.writeStartDocument();
    bool ignore = false;
    static const QString searchString = "C";
    while (!inputStream.atEnd() && !inputStream.hasError())
    {
        inputStream.readNext();
        if (inputStream.isStartElement()) {
            QString name = inputStream.name().toString();
            if (name != searchString && !ignore)
                outputStream.writeStartElement(name);
            else
                ignore = true;
        } else if (inputStream.isEndElement()) {
            if (!ignore)
                outputStream.writeEndElement();
            if (inputStream.name().toString() == searchString)
                ignore = false;
        }
    }
    outputStream.writeEndDocument();
    return 0;
}

main.pro

TEMPLATE = app
TARGET = main
QT = core
SOURCES += main.cpp

Build and Run

qmake && make && ./main

QtXml

If you still insist on using QtXml for this simple task, you could do this:

main.cpp

#include <QDomDocument>
#include <QDomNode>
#include <QDomElement>
#include <QFile>
#include <QDebug>

int main()
{
    QFile inputFile("testin.xml");
    if (!inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "File open error:" << inputFile.errorString();
        return 1;
    }

    QDomDocument doc;
    doc.setContent(&inputFile);
    QDomNode searchNode = doc.elementsByTagName("C").item(0);
    QDomNode parentNode = searchNode.parentNode();
    parentNode.removeChild(searchNode);
    qDebug() << doc.toString();
    return 0;
}

main.pro

TEMPLATE = app
TARGET = main
QT = core xml
SOURCES += main.cpp

Build and Run

qmake && make && ./main

Output

"<A>
 <B/>
</A>
"