15

I need to edit the text of a QDomElement - Eg

I have an XML file with its content as -

<root>    
    <firstchild>Edit text here</firstchild>
</root>

How do I edit the text of the child element <firstchild>?

I don't see any functions in the QDomElement of QDomDocument classes descriptions provided in Qt 4.7

Edit1 - I am adding more details.

I need to read, modify and save an xml file. To format of the file is as below -

<root>    
    <firstchild>Edit text here</firstchild>
</root>

The value of element needs to be edited.I code to read the xml file is -

QFile xmlFile(".\\iWantToEdit.xml");
xmlFile.open(QIODevice::ReadWrite);

QByteArray xmlData(xmlFile.readAll());

QDomDocument doc;
doc.setContent(xmlData);

// Read necessary values

// write back modified values?

Note: I have tried to cast a QDomElement to QDomNode and use the function setNodeValue(). It however is not applicable to QDomElement.

Any suggestions, code samples, links would we greatly welcome.

Community
  • 1
  • 1
Eternal Learner
  • 3,800
  • 13
  • 48
  • 78

6 Answers6

24

This will do what you want (the code you posted will stay as is):

// Get element in question
QDomElement root = doc.documentElement();
QDomElement nodeTag = root.firstChildElement("firstchild");

// create a new node with a QDomText child
QDomElement newNodeTag = doc.createElement(QString("firstchild")); 
QDomText newNodeText = doc.createTextNode(QString("New Text"));
newNodeTag.appendChild(newNodeText);

// replace existing node with new node
root.replaceChild(newNodeTag, nodeTag);

// Write changes to same file
xmlFile.resize(0);
QTextStream stream;
stream.setDevice(&xmlFile);
doc.save(stream, 4);

xmlFile.close();

... and you are all set. You could of course write to a different file as well. In this example I just truncated the existing file and overwrote it.

Lucky Luke
  • 1,373
  • 2
  • 13
  • 18
  • 1
    @Eternal Learner: Don't forget to aware the bounty as well!! – Goz Jul 26 '11 at 22:19
  • 5
    Well actually, the text inside is a text node, so you can just do this as follows: doc.documentElement().firstChildElement("firstchild").firstChild().setNodeValue("new text"); // notice the extra firstChild() query – Petar Apr 16 '14 at 20:20
  • Prefect solution given by Luke,it is useful when you update second child element. Peter's solution is Optimal and works for quick xml update, no need to variable declaration like QDomElement and QDomText and roor.replaceChild(), Thank you – Milind Morey Jul 20 '20 at 13:48
8

Just to update this with better and simpler solution (similar like Lol4t0 wrote) when you want to change the text inside the node. The text inside the 'firstchild' node actually becomes a text node, so what you want to do is:

...
QDomDocument doc;
doc.setContent(xmlData);
doc.firstChildElement("firstchild").firstChild().setNodeValue(‌​"new text");

notice the extra firstChild() call which will actually access the text node and enable you to change the value. This is much simpler and surely faster and less invasive than creating new node and replacing the whole node.

Petar
  • 1,034
  • 1
  • 12
  • 18
3

what is the problem. What sort of values do you want to write? For example, the fallowing code converts this xml

<?xml version="1.0" encoding="UTF-8"?>
<document>
    <node attribute="value">
        <inner_node inner="true"/>
        text
    </node>
</document>

to

<?xml version='1.0' encoding='UTF-8'?>
<document>
    <new_amazing_tag_name attribute="foo">
        <bar inner="true"/>new amazing text</new_amazing_tag_name>
</document>

Code:

QFile file (":/xml/document");
file.open(QIODevice::ReadOnly);
QDomDocument document;
document.setContent(&file);
QDomElement documentTag = document.documentElement();
qDebug()<<documentTag.tagName();

QDomElement nodeTag = documentTag.firstChildElement();
qDebug()<<nodeTag.tagName();
nodeTag.setTagName("new_amazing_tag_name");
nodeTag.setAttribute("attribute","foo");
nodeTag.childNodes().at(1).setNodeValue("new amazing text");

QDomElement innerNode = nodeTag.firstChildElement();
innerNode.setTagName("bar");
file.close();

QFile outFile("xmlout.xml");
outFile.open(QIODevice::WriteOnly);
QTextStream stream;
stream.setDevice(&outFile);
stream.setCodec("UTF-8");
document.save(stream,4);
outFile.close();
Lol4t0
  • 12,444
  • 4
  • 29
  • 65
  • The setNodevalue function works only for certain element types. Have a look at the method `QString QDomNode::nodeValue () const` in the Qt documentation. They provide a list of nodes for which the setNodeValue is applicable. I need to set the value of a `QDomELement`. – Eternal Learner Jul 25 '11 at 15:43
  • You are wrong. As you can see in my example, `QDomElement` _does not contain any text directly_. but it contains `QDomText` element, which contains your text. If `QDomElement` contain text directly, when replacing it, you would erase all child nodes of the element. – Lol4t0 Jul 25 '11 at 16:40
2

Here is a version of your code that does what you need. Note as spraff said, the key is finding the child of the "firstchild" node of type text - that's where the text lives in the DOM.

   QFile xmlFile(".\\iWantToEdit.xml");
    xmlFile.open(QIODevice::ReadWrite);

    QByteArray xmlData(xmlFile.readAll());

    QDomDocument doc;
    doc.setContent(xmlData);

    // Get the "Root" element
     QDomElement docElem = doc.documentElement();

    // Find elements with tag name "firstchild"
    QDomNodeList nodes = docElem.elementsByTagName("firstchild"); 

    // Iterate through all we found
    for(int i=0; i<nodes.count(); i++)
    {
        QDomNode node = nodes.item(i);

        // Check the node is a DOM element
        if(node.nodeType() == QDomNode::ElementNode)
        {
            // Access the DOM element
            QDomElement element = node.toElement(); 

            // Iterate through it's children
            for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling())
            {
                // Find the child that is of DOM type text
                 QDomText t = n.toText();
                 if (!t.isNull())
                 {
                    // Print out the original text
                    qDebug() << "Old text was " << t.data();
                    // Set the new text
                    t.setData("Here is the new text");
                 }
            }
        }
    }

    // Save the modified data
    QFile newFile("iEditedIt.xml");
    newFile.open(QIODevice::WriteOnly);
    newFile.write(doc.toByteArray());
    newFile.close();
docsteer
  • 2,506
  • 16
  • 16
  • This worked for me, when I changed the line reading "QDomText t = n.toText();" to instead read "QDomText t = n.firstChild().toText();". – myk Oct 07 '17 at 00:53
0
Here is Solution to update xml tag using QdomDocument,It's work for linux ubuntu 18.04  
 steps is open xmlfile in readwrite mode, setContent of file in object of qdomdocument,update node value, save xmlfile and close xmlfile.

        QString filepath= QDir::homePath() + "/Book.xml";
        QFile file (filepath);
        file.open(QIODevice::ReadWrite);
        QDomDocument doc;
        doc.setContent(&file); doc.documentElement().firstChildElement("BookPrice").firstChild().setNodeValue(QString("$7777"));
         file.resize(0);
         QTextStream stream;
         stream.setDevice(&file);
         doc.save(stream, 4);
         file.close();
Milind Morey
  • 2,100
  • 19
  • 15
-2

Go up an abstraction level to QDomNode. firstchild is a QDomText element so you can get value() and setValue(x) to work with the text itself.

spraff
  • 32,570
  • 22
  • 121
  • 229
  • QDomNode::firstChild returns QDomNode and not QDomText. – Eternal Learner Jul 22 '11 at 21:47
  • And the QDomNode in question *is a* QDomText. Check the inheritence tree. You check the node type at runtime [and convert it](http://doc.qt.nokia.com/latest/qdomnode.html#toText) – spraff Jul 25 '11 at 08:14
  • 1
    No, `firstchild` is `QDomElement`. And it has a child `QDomText`. I checked it. – Lol4t0 Jul 25 '11 at 18:21