Remove child nodes from parent - PugiXML - c++

<Node>
<A>
<B id = "it_DEN"></B>
</A>
<A>
<B id = "en_KEN"></B>
</A>
<A>
<B id = "it_BEN"></B>
</A>
</Node>
How can I remove child node of <A></A> that has child node <B></B> which has attribute id not starts with it using PugiXML.
The result would be as below:
<Node>
<A>
<B id = "it_DEN"></B>
</A>
<A>
<B id = "it_BEN"></B>
</A>
</Node>

This is slightly tricky if you want to remove nodes while iterating (to keep the code single-pass). Here's one way to do it:
bool should_remove(pugi::xml_node node)
{
const char* id = node.child("B").attribute("id").value();
return strncmp(id, "it_", 3) != 0;
}
for (pugi::xml_node child = doc.child("Node").first_child(); child; )
{
pugi::xml_node next = child.next_sibling();
if (should_remove(child))
child.parent().remove_child(child);
child = next;
}
Alternatively you can just use XPath and remove the results:
pugi::xpath_node_set ns = doc.select_nodes("/Node/A[B[not(starts-with(#id, 'it_'))]]");
for (auto& n: ns)
n.node().parent().remove_child(n.node());

Another way is to increment the iterator before removing the child. To remove an attribute while iterating.
for(pugi::xml_attribute_iterator it = node.attributes_begin(); it != node.attributes_end();){
pugi::xml_attribute attr = *it++;
if(should_remove(attr)){
node.remove_attribute(attr);
}
}

Related

pugixml. how to get all of the substructure from node, if not known in advance where it is located?

In all the examples pugixml which I have encountered, anywhere parse tree, if known, where is located node in tree structure. But what if you do not know where is the node, and only knows her name.
I have an example of the input string:
<data>
.......
<name not known1>
<name not known2>
........ <!-- maybe something sub node>
<need node>
<Name>student 1</Name>
<Roll>111</Roll>
</need node>
........ <!-- maybe something sub node>
</name not known2>
</name not known1>
<name not known3>
........ <!-- maybe something nodes>
<need node>
<Name>july 1</Name>
<new data>444</new data>
<data5>444</data5>
<node>
<data>student class 4</data>
</node>
</need node>
........ <!-- maybe something nodes>
</name not known3>
.......
</data>
Please tell me how to use pugixml to find and get all the substructure(and values) of all nodes "need node" from all xml document? If I don't know where they are located in the tree structure.
The easiest way is to use XPath. Assuming "need node" is named "information", you could get all nodes with this name, iterate through them and get data from the resulting nodes:
pugi::xpath_node_set ns = doc.select_nodes("//information");
// if you don't have C++11, use for (size_t i = 0; i < ns.size(); ++i)
for (pugi::xpath_node n: ns)
{
pugi::xml_node node = n.node();
const char* name = n.child("Name").text().get();
// ...
}

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();

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.

Why is this loop only running once?

Why is this loop only running once?
noteDatabaseItem just takes a node and fills in the data. the xml has 3 notes in it.
XML:
<?xml version="1.0" encoding="utf-8"?>
<noteCollection>
<note name="Test Note 1">This is test note 1 content!</note>
<note name="Test Note 2">This is test note 2 content!</note>
<note name="Test Note 3">This is test note 3 content!</note>
</noteCollection>
C++:
std::vector<notekeeper::noteDatabaseItem> noteList;
TiXmlElement* noteCollection = xmlDoc->FirstChildElement("noteCollection");
TiXmlElement* node = noteCollection->FirstChildElement("note");
int itemCount = 0;
while (node != NULL) {
itemCount++;
noteList.resize(itemCount);
noteList.push_back(noteDatabaseItem(node));
node = noteCollection->NextSiblingElement("note");
}
Shouldn't it be node = node->NextSiblingElement("note")?
noteCollection has only children, not siblings, right?
You're getting the wrong element in your loop. Try this:
while (node != NULL) {
itemCount++;
noteList.push_back(noteDatabaseItem(node));
node = node->NextSiblingElement("note");
}
The next sibling of the current node is the one you want. You were trying to get the next sibling of the parent node.
node = noteCollection->NextSiblingElement("note");
is meant to be
node = node->NextSiblingElement("note");
Stupid mistake. Sibling not Child.