Xpath How remove child node by attribute c++ libxml2 - c++

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.

Related

Remove child nodes from parent - PugiXML

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

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
}
}

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.