问题
I am using boost 1.55.0 on ubuntu 12.04lts with clang 3.4.
I have a boost::property_tree::ptree
whose xml input looks like:
<root>
<persons>
<person>
<name>dad</name>
<age>43</age>
</person>
<person>
<name>me</name>
<age>4</age>
</person>
</persons>
</root>
So I have a list of nodes with the same tag.
To read them I iterate over the tree, and depending on a condition I want to erase a node. This looks like:
boost::property_tree::ptree pt;
boost::property_tree::read_xml(inputFileName, pt);
boost::property_tree::ptree& persons = pt.get_child("root");
for(boost::property_tree::ptree::const_iterator it = persons.begin(); it != persons.end(); ++it)
{
std::string name = it->second.get<std::string>("name");
if(name == "dad")
// erase that name node from pt
persons.erase(it->second.find("name"); // this doesn't work
}
[Edit]As the answer from pmr supposes, I wrote the following code:
boost::property_tree::ptree::iterator i = persons.begin();
auto assoc_i = it->second.find("name");
auto ci = persons.to_iterator(assoc_i);
std::advance(i, std::distance<boost::property_tree::ptree::const_iterator>(iterator, ci)); // --> here it hangs
persons.erase(i);
Now it compiles, and the application does not crash, but it hangs at the mentioned position. And I don't know why. [/Edit]
Many thanks in advance.
回答1:
Your issue at hand has little to do with the constness of the iterators, you are simply erasing with the wrong ptree iterator.
ptree& persons = pt.get_child("root.persons");
for(auto it = persons.begin(); it != persons.end();) {
if(it->second.get<string>("name") == "dad")
it = persons.erase(it);
else
++it;
}
The ptree uses a multi_index for sub-nodes, and to keep an iteration stable over erasures, you must use the iterator returned from the erase() operation to continue the iteration, a common pattern.
Note that the XML in the question has an /
(</age>
) termination missing, it wouldn't validate. I am not editing the question to fix it since this could be one of the problems that you experience with the execution of the program.
Output of processing the ptree with the above code via write_xml(std::out, pt)
:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<persons>
<person>
<name>me</name>
<age>4</age>
</person>
</persons>
</root>
回答2:
C++11 APIs for containers specify a member function iterator container::erase(const_iterator, const_iterator)
. Unfortunately, basic_ptree
does not do that, so you are stuck with old C++ way of converting a const_iterator
to an iterator
:
// tree is your ptree, my_const_iter a ptree::const_iterator
ptree::iterator i = tree.begin();
advance (i, std::distance<ConstIter>(i,my_const_iter));
来源:https://stackoverflow.com/questions/21427518/property-tree-put-erase-with-const-iterator-or-how-to-convert-const-iterator-to