2017-05-04 7 views
1

Pourriez-vous s'il vous plaît aidez-moi de ce qui suit?Comment effacer un enfant de l'arbre boost s'il est enregistré deux fois?

Je finalTree = renseigner ce arbora + treeB

Cependant, le problème est que certains éléments de treeB ont le même nom avec certains des arbora. En conséquence, je pourrais avoir des doubles registres pour certains enfants.

ie.

<category> 
     <fruit type="banana"> 
       <characteristic> 
       <point v="0"/> 
       </characteristic> 
     </fruit> 
     <fruit type="orange"> 
       <characteristic> 
       <point v="1"/> 
       </characteristic> 
     </fruit> 
     <fruit type="banana"> 
       <characteristic> 
        <point v="2"/> 
       </characteristic> 
     </fruit> 
     <fruit type="fig"> 
       <characteristic> 
       <point v="3"/> 
       </characteristic> 
     </fruit> 
    </category> 

Ce que je veux accomplir est de supprimer la première entrée de banane et garder le dernier. Jusqu'à présent, je le veux

boost::property_tree::ptree & node = informationTree.add("information.fruitTypes", ""); 
node.add("<xmlattr>.type", fruit); 
node.add_child("characteristic", char); 

Le problème est que je ne sais pas comment l'enlever, comme je ne sais pas si la double entrée sera banane ou autre chose la prochaine fois. Dois-je copier l'arbre peuplé? Que suggérez-vous s'il vous plaît?

Répondre

0

Si vous construisez simplement l'arbre, vous pouvez simplement utiliser put_* au lieu de add_* et il écraserait un élément s'il existe déjà sous ce nom.

Si vous avez un arbre et que vous voulez supprimer les doublons à un certain sous-arbre, vous devez le faire manuellement, par exemple:

Live On Coliru

#include <boost/property_tree/xml_parser.hpp> 
#include <iostream> 
#include <map> 
using boost::property_tree::ptree; 

template <typename KeyF> 
ptree nodup(ptree const& pt, KeyF key_accessor) { 
    ptree filtered; 
    std::map<std::string, std::reference_wrapper<ptree> > seen; 

    for (auto& entry : pt) { 
     auto key  = key_accessor(entry); 
     auto previous = seen.find(key); 

     if (seen.end() == previous) 
      seen.emplace(key, filtered.add_child(entry.first, entry.second)); 
     else 
      previous->second.get() = entry.second; // overwrite 
    } 

    return filtered; 
} 

int main() { 
    ptree pt; 
    { 
     std::istringstream iss("<category><fruit type=\"banana\"><characteristic><point v=\"0\"/></characteristic></fruit><fruit type=\"orange\"><characteristic><point v=\"1\"/></characteristic></fruit><fruit type=\"banana\"><characteristic><point v=\"2\"/></characteristic></fruit><fruit type=\"fig\"><characteristic><point v=\"3\"/></characteristic></fruit></category>"); 
     read_xml(iss, pt); 
    } 
    write_xml(std::cout, pt, boost::property_tree::xml_writer_make_settings<std::string>(' ', 4, "utf-8")); 

    auto& subtree = pt.get_child("category"); 
    subtree = nodup(subtree, [](ptree::value_type const& item) { return item.second.get("<xmlattr>.type", ""); }); 

    write_xml(std::cout, pt, boost::property_tree::xml_writer_make_settings<std::string>(' ', 4, "utf-8")); 
} 

Si vous êtes un peu Plus les performances concernées, vous pouvez itérer en arrière et éviter certaines actions d'écrasement:

Live On Coliru

template <typename KeyF> 
ptree nodup(ptree const& pt, KeyF key_accessor) { 
    ptree filtered; 
    std::map<std::string, std::reference_wrapper<ptree> > seen; 

    for (auto entry = pt.rbegin(), last = pt.rend(); entry != last; ++entry) { 
     auto key  = key_accessor(*entry); 
     auto previous = seen.find(key); 

     if (seen.end() == previous) 
      seen.emplace(key, filtered.add_child(entry->first, entry->second)); 
    } 

    return filtered; 
} 

Cependant, gardez à l'esprit cela modifie potentiellement l'ordre dans lequel les fruits apparaissent dans le sous-arbre.