How to delete nested xml element using qt - c++

i have xml file like this
<root>
<element>
<child id = "0"> Some Text </child> <-- Target To Delete
</element>
<element>
<child id = "1"> Some Text </child>
</element>
</root>
how can i delete child element of id "0" ? using Qt library.

QDomDocument doc;
doc.setContent(oldXml);
QDomNodeList nodes = doc.elementsByTagName("element");
for (int i = 0; i < nodes.count(); ++i)
{
QDomNode node = nodes.at(i);
QDomElement child = node.firstChildElement("child");
if (!child.isNull() && child.attribute("id") == "0")
{
node.removeChild(child);
}
}
QString newXml = doc.toString();

Related

QT DOMXml - Change the name of a node [duplicate]

This question already has answers here:
Edit Value of a QDomElement?
(6 answers)
Closed 6 years ago.
I am working on a QT Project and part of that is a reconstruction of an XML file. I was able to make most of the needed changes with QDom but I can't find how to rename a node.
So the old XML file looks like ..
<root>
<window name="" ..>
<element x="" y=""/>
<element1 a="" b=""/>
...
</window>
..
..
<window name="">
<element x="" y=""/>
<element1 a="" b=""/>
...
</window>
</root>
How can i change the XML so that the new one will have < group > instead of < window >?
So at the end it needs to look like..
<root>
<group name="" ..>
<element x="" y=""/>
<element1 a="" b=""/>
...
</group>
..
..
<group name="">
<element x="" y=""/>
<element1 a="" b=""/>
...
</group>
</root>
Adding some more info...
Here is the code I use to read the <window> nodes, delete some based on the visibility (comes from a list) and I need to change <window> to <group> for the remaining nodes.
QFile oldXml("file.xml");
oldXml.open(QIODevice::ReadOnly);
QDomDocument doc;
doc.setContent(&oldXml);
QDomNodeList nodes = doc.elementsByTagName("window");
// Remove Window nodes based on visibility
insize = nodes.length();
for ( int i = 0; i < insize; i++ ) {
QDomNode node = nodes.at(i-dels);
if ( (list2[i] == "0") | (list2[i]=="") ) {
node.parentNode().removeChild(node);
dels=dels+1;
} else {
// Here is where i need to change the node name from <window> to e.g. <group>
}
}
You could use setTagName and maybe setAttribute if you want to set a value for the name attribute.
With the following example, myxml.xml is converted to xmlout.xml
Note#1: this is just an example: we're replacing only the first node.
Note#2: in this example, we're using two different files. Depending on your design, you could use the same or not.
myxml.xml
<root>
<window name="">
<element x="" y=""/>
<element1 a="" b=""/>
</window>
<window name="">
<element x="" y=""/>
<element1 a="" b=""/>
</window>
</root>
xmlout.xml
<root>
<group name="value">
<element y="" x=""/>
<element1 a="" b=""/>
</group>
<window name="">
<element y="" x=""/>
<element1 a="" b=""/>
</window>
</root>
main.cpp
#include <iostream>
#include <QtXml>
#include <QFile>
int main(int argc, char *argv[])
{
QDomDocument doc;
// Load xml file as raw data
QFile inFile(":myxml.xml");
if (!inFile.open(QIODevice::ReadOnly ))
{
std::cerr << "Error - inFile: " << inFile.errorString().toStdString();
return 1;
}
// Set data into the QDomDocument before processing
doc.setContent(&inFile);
// Get element in question
QDomElement root = doc.documentElement();
QDomElement nodeTag = root.firstChildElement("window");
nodeTag.setTagName("group");
nodeTag.setAttribute("name","value");
inFile.close();
// Save the modified data
QFile outFile("xmlout.xml");
if (!outFile.open(QIODevice::WriteOnly ))
{
// Error while loading file
std::cerr << "Error - outFile: " << outFile.errorString().toStdString();
return 1;
}
QTextStream stream;
stream.setDevice(&outFile);
stream.setCodec("UTF-8");
doc.save(stream,4);
outFile.close();
return 0;
}
I did not see any straight API function to rename the element. API is allowing to change value but not name.
There is another round about way.
Create an element, for example:
QDomElement group = doc.createElement("group");
use "QDomNode's replacechild" function.
QDomNode QDomNode::replaceChild(const QDomNode &newChild, const QDomNode &oldChild)
ex:
QDomNode dNode = node.replaceChild(group,oldNode);

Deleting specific node of XML file

Below I have a sample of my XML file, I want to delete a specific node in each header. How do i do it. for example in header<HEADER> i want to delete the node <ADDRESS>, not just its attribute but the whole node. in <HEADER1> I need to delete the attribute <UMG_VAR Name="ABC" Value=1></UMG_var>, here Name attribute is unique.
<MAIN>
<HEADER>
<TITLE>ppc_ph_pios</TITLE>
<AUTOR>DNL</AUTOR>
<AGE>age</AGE>
<SEX>Male</SEX>
<PLACE>Earth</PLACE>
<ADDRESS>abc</ADDRESS>
</HEADER>
<HEADER1>
<UMG_VAR Name="RED" Value="3"></UMG_VAR>
<UMG_VAR Name="ABC2" Value="2"></UMG_VAR>
<UMG_VAR Name="ABC" Value="1"></UMG_VAR>
</HEADER2>
</MAIN>
QDomDocument doc;
doc.setContent(oldXml);
QDomNodeList nodes = doc.elementsByTagName("element");
for (int i = 0; i < nodes.count(); ++i)
{
QDomNode node = nodes.at(i);
QDomElement child = node.firstChildElement("child");
if (!child.isNull() && child.attribute("id") == "0")
{
node.removeChild(child);
}
}
QString newXml = doc.toString();

Extracting sub-tree XML string with TinyXml2

I want to do the exact same thing as the guy in this question.
I want to convert an XML child element (and all of its children) to an XML string, so if the XML structure were
<parent>
<child>
<value>abc</value>
</child>
<parent>
I want the xml for the child element, e.g.
<child>
<value>abc</value>
</child>
I don't care about whitespace. The problem is that the accepted answer from the other question appears to be out of date, because there is no "Print" method for XMLElement objects. Can I do this with TinyXml2?
I coded up the following function that does the trick for me. Please note that it may have bugs- I am working with very simple XML files, so I won't pretend that I have tested all cases.
void GenXmlString(tinyxml2::XMLElement *element, std::string &str)
{
if (element == NULL) {
return;
}
str.append("<");
str.append(element->Value());
str.append(">");
if (element->GetText() != NULL) {
str.append(element->GetText());
}
tinyxml2::XMLElement *childElement = element->FirstChildElement();
while (childElement != NULL) {
GenXmlString(childElement, str);
childElement = childElement->NextSiblingElement();
}
str.append("</");
str.append(element->Value());
str.append(">");
}

C++ Pugixml get children of parent by attribute id

For example:
<levels>
<level id="1">
<somestuff></somestuff>
</level>
<level id="2">
<somestuff></somestuff>
</level>
</levels>
How do you get the data of level with id 1?
Now i am using pugi::xml_node level = levels.child("level") But that return all levels..
Regards,
GJJ
levels.find_child_by_attribute("level", "id", "1")
Try it:
for (pugi::xml_node ambil = doc.child("levels").child("level"); ambil; ambil = ambil.next_sibling("level"))
{
int id = ambil.attribute("id").as_int();
CCLog("%d",id);
}
foreach children & compare attribute value.
e.g.
for (const auto& node : levels.children("level"))
{
if (node.attribute("id").as_int() == 1)
{
// TODO: add ur code here
}
}

Xpath How remove child node by attribute c++ libxml2

How do I remove a child with a specific attribute? I´m using c++/libxml2. My attempt so far (in the example I want to remove child node with id="2"):
Given XML:
<p>
<parent> <--- current context
<child id="1" />
<child id="2" />
<child id="3" />
</parent>
</p>
xmlNodePtr p = (parent node)// Parent node, in my example "current context"
xmlChar* attribute = (xmlChar*)"id";
xmlChar* attribute_value = (xmlChar*)"2";
xmlChar* xml_str;
for(p=p->children; p!=NULL; p=p->next){
xml_str = xmlGetProp(p, attribute);
if(xml_str == attribute_value){
// Remove this node
}
}
xmlFree(xml_str);
Call xmlUnlinkNode to remove a node. Call xmlFreeNode to free it afterward, if you want:
for (p = p->children; p; ) {
// Use xmlStrEqual instead of operator== to avoid comparing literal addresses
if (xmlStrEqual(xml_str, attribute_value)) {
xmlNodePtr node = p;
p = p->next;
xmlUnlinkNode(node);
xmlFreeNode(node);
} else {
p = p->next;
}
}
Haven't used this library in a while, but check out this method. Note that per the description, you need to call xmlUnlinkNode first.