3

I want to delete a node from a boost property tree, but I want to preserve its children and connect them to the parent of the deleted node (i.e. to their grandparent node). Is there an elegant way to achieve this?

Marste
  • 627
  • 7
  • 22

2 Answers2

4

This might be the most efficient way to move the grandchildren:

std::move(middle.begin(), middle.end(), back_inserter(parent));

Full sample

Live On Coliru

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;

int main() {

    std::istringstream iss(R"({ "a" : { "middle" : { "a1":1, "a2":2, "a3":3 }, "more":"stuff" } })");
    ptree pt;
    read_json(iss, pt);

    auto& parent = pt.get_child("a");
    auto& middle = pt.get_child("a.middle");

    std::move(middle.begin(), middle.end(), back_inserter(parent));
    parent.erase("middle");

    write_json(std::cout, pt);

}

Sample json output:

{
    "a": {
        "more": "stuff",
        "a1": "1",
        "a2": "2",
        "a3": "3"
    }
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • For this to be effective, doesn't `property_tree` need to support move? (move constructor/move assignment). I didn't find a single `&&` (l-value ref) in the whole source code of `proporty_tree`. Am I missing something? – alfC Sep 23 '17 at 07:13
  • 1
    @alfC Firstly, rule-of-zero means you can have move semantics without a single `&&` sign. Secondly, the iterators point into a multi-index-container (so need to look there). That's is [a missing feature](https://stackoverflow.com/questions/46082394/move-element-from-boost-multi-index-array). For now, `ptree` could add a `splice` operation, which would naturally wrap `multi_index`'s [list operations](http://www.boost.org/doc/libs/1_65_1/libs/multi_index/doc/reference/seq_indices.html#list_operations): I just made a [**draft** implementation](https://github.com/boostorg/property_tree/pull/30) – sehe Sep 23 '17 at 09:48
  • rule zero: good point if there no constructor/destructor or anything and it is implemented in terms of a movable type then you have move for free? is that what you mean? I doubt, whatever the class is, in this case that it has zero special functions. So, in summary are you saying that `ptree` is implemented in terms of `multi_index` but in its turn it doesn't have move implemented yet? I guess your code is still correct, because as soon as move is implement down the road this code will run faster that if written with `std::copy`. – alfC Sep 23 '17 at 09:59
  • Agreed on all accounts, @alfC – sehe Sep 23 '17 at 10:14
  • Just to confirm that this not just a property of ptree iterators... Is this the best way to contruct a complicated tree? Construct the leaf outside and then move it? `{ boost::property_tree::ptree pt_sub; recursive_populate(pt_sub); pt.add_child(name, std::move(pt_sub));}` – alfC Sep 23 '17 at 10:18
  • 1
    I'd suggest `ptree& pt_sub = pt.add_child(name, {}); recursive_populate(pt_sub);` instead @alfC (And no it's not just a property of ptree iterators. `std::set<>` e.g. has the same semantics) – sehe Sep 23 '17 at 10:39
  • Ah, ok, I didn't realize that `add_child would return a reference, I though it returned an iterator and then didn't work with the iterator syntax. – alfC Sep 23 '17 at 11:25
0

I had to do something similar.

I used an iterator with recursion and copied the child before removing the node and branching it back on a newly created one.

But I guess the full copy of each trees before removing to be quite resources-consuming so you can only do it with relatively small trees and it isn't really elegant.

eMixam
  • 137
  • 1
  • 10