c++pugixml

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>

Solution

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