How to make a deep copy of an entire QDomDocument - c++

I want to create a deep copy of a QDomDocument in an xml model in order to allow the user to later restore the document to its original state. The QDomDocument documentation says that this can be achieved by using cloneNode(). However, cloneNode() returns a QDomNode, not a QDomDocument, and I can't seem to figure out how how to properly add it to a new document.
I've tried:
QDomDocument copy;
copy.importNode(existingDocument.cloneNode(true),true);
and
QDomDocument copy;
copy.appendChild(existingDocument.cloneNode(true),true);
but neither work.

If you have a QDomNode, you can use its toDocument function.
Assuming QDomNode node is the node returned from cloneNode()
QDomDocument newDocument = node.toDocument();

Related

Is it necessary to make QDomElement created by the same QDomDocument to write XML?

I use QDomDocument to write XML document.
But in my dom tree, some nodes are created using docA, some using docB.
QDomElement parentNode = docA.CreateElement("name");//created by docA
QDomElement childNode = docB.CreateElement("value");//created by docB
parentNode.appendChild(childNode);//in onr tree
And:
QTextStream out(&file);
docA.save(out, Indent);//docA created the root QDomElement
//write the file using docA
So is it possible to write the whole tree to XML like this?
You should avoid this because things will start going wrong when if docA goes out of scope if docB is still being used. I believe what you're proposing will technically work until that occurs, but the library seems designed to discourage it.
However, there is a function QDomDocument::importNode() which is probably what you want. You can do something like this:
docAParent.appendChild( docA.importNode( docBNode, true ) );
The boolean argument controls whether or not a deep copy is made.
See the documentation: http://qt-project.org/doc/qt-4.8/qdomdocument.html#importNode

How do I delete a top level QTreeWidgetItem from a QTreeWidget?

I'm attempting to remove a top level tree widget item if there are no child nodes within the top level item. What is the correct way to do this? I can't seem to find the API call within Qt's documentation. Is it safe to just call delete on the top level tree widget item? I haven't run into any issues yet, but I'd like to know if that's safe practice. Thanks much.
if(topLevelTreeWidgetItem->childCount() > 1) {
topLevelTreeWidgetItem->removeChild(childItem);
}
else
{
delete topLevelTreeWidgetItem;
}
deleteing a QTreeWidgetItem directly is perfectly safe.
According to the documentation for ~QTreeWidgetItem():
Destroys this tree widget item. The item will be removed from
QTreeWidgets to which it has been added. This makes it safe to delete
an item at any time.
I've used delete on many QTreeWidgetItems in practice and it works quite well.
To delete a top level item call QTreeWidget::takeTopLevelItem method and then delete the returned item:
delete treeWidget->takeTopLevelItem(index);
Where index is index of the item to be removed.
Function takeChild only works with QTreeWidgetItem. With QtreeWidget, you can use QtreeWidget::takeTopLevelItem(int index)

How to debug QDomElement in QtXml?

I've got a QDomElement, and I would like to debug it, i.e. see it as plain text in debug console. In order to output it with qDebug(), it needs to be in QString format, however I don't see any conversion method from a QDomElement nor a QDomNode.
Any idea? Thanks!
There is no built-in operator for streaming DOM elements to QDebug. You could write one easily enough, something like:
QDebug operator<<(QDebug dbg, const QDomNode& node)
{
QString s;
QTextStream str(&s, QIODevice::WriteOnly);
node.save(str, 2);
dbg << qPrintable(s);
return dbg;
}
Use QTextStream:
QTextStream lTS(stdout);
lTS << lMyDomElement;
if you #include <QDebug> QDebug would act as TextStream itself.
i.e. qDebug()<< lMyDomElement; would be enough)
Well I also come across similar situations, in that case my best bet is to make use of the QDomDocument which this QDomElement is part of. So I would say you cannot get a direct way to access the QDomElement but you can achieve that using the QDomDocument.
For this you need to ensure that your QDomDocument gets updated with the recent QDomElement and then use QDomDocument::toString() which would return you the whole document as a QString.
Here is the Qt reference.
Hope this helps.

QDomDocument won't insert QDomElement

I'm doing something with XML and now I'm confused.
This code works perfectly:
QDomElement new_item = doc.createElement(name);
new_item.setAttribute("type", value.typeName());
new_item.setAttribute("value", value.toString());
doc.elementsByTagName(section).at(0).appendChild(new_item);
But if I would create QDomElement myself (without calling createElement method), then it doesn't get inserted into the document. Something like this doesn't work:
QDomElement new_item;
new_item.setTagName(name);
new_item.setAttribute("type", value.typeName());
new_item.setAttribute("value", value.toString());
doc.elementsByTagName(section).at(0).appendChild(new_item);
Can anyone explain to me why I need to use createElement method ?
Thank you :)
Basically DomElement creation needs information that QDomDocument has. From Qt 4.7 documentation
Since elements, text nodes, comments, processing instructions, etc., cannot exist outside the context of a document, the document class also contains the factory functions needed to create these objects. The node objects created have an ownerDocument() function which associates them with the document within whose context they were created.
http://doc.qt.io/archives/qt-4.7/qdomdocument.html#details (third paragraph)

How do I append elements with duplicate names using MSXML & C++?

I am write some code to update a XML DOM using MSXML4 & C++. I need a method that appends a child element to a parent element. The code I have written below works until the title of the child matches the title of another child under the parent. I cannot change the title of the children so I need to find a way to append them to the parent.
Can anyone provide some guidance?
// this call creates '<parent><child/></parent>'
AppendChild("/root/parent", "child");
// this call attempts to create '<parent><child/><child/></parent>' but the DOM remains unchanged ('<parent><child/></parent>')
AppendChild("/root/parent", "child");
void AppendChild(const std::string kPathOfParent, const std::string kNameOfChild)
{
MSXML2::IXMLDOMNodePtr pElement = m_pXmlDoc->createNode(NODE_ELEMENT, kNameOfChild.c_str(), m_xmlns.c_str());
MSXML2::IXMLDOMNodePtr pParent = m_pXmlDoc->selectSingleNode(kPathOfParent.c_str());
MSXML2::IXMLDOMNodePtr pNewChild = pParent->appendChild(pElement);
}
I am not sure exactly what the problem was, but somewhere my binaries were out of step. I rebuilt the entire project via 'Clean Solution' instead of just the 'Build Solution' option. Now both children are created using the code above. It is not clear to me why I was able to step in to the code via the debugger, but the second child was never created until I cleaned the solution.
Jeff & Remy, thank-you for your comments.