Search code examples
c++c++11boostboost-propertytree

C++: boost ptree relative key


In C++ using ptree from boost, I need to find the relative key to access a.b.c2.e1 from a.b. This key is c2.e1. How can I write a function which finds this relative key?

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

using namespace boost::property_tree;

std::string relative_key(const ptree &p1,const ptree &p2)
{
    ??????????????
    // return "b.c2.e1";
}

int main()
{
    ptree pt0;

    pt0.put("a.b.c1",4);
    pt0.put("a.b.c2.e1",4);
    pt0.put("a.b.c4",4);
    pt0.put("a.d",4);
    pt0.put("k.m",4);
    pt0.put("k.n",4);

    ptree &pt_e1=pt0.get_child("a.b.c2.e1");
    ptree &pt_b=pt0.get_child("a.b");

    std::cout<<relative_key(pt_e1,pt_b)<<std::endl;

    return 0;
}

Solution

  • You'd need to write a recursive search function, like:

    bool find_subtree_helper(ptree const& haystack, ptree const& needle, path_type& path) {
        if (std::addressof(haystack) == std::addressof(needle))
            return true;
    
        for (auto& child : haystack) {
            auto next = path;
            next /= child.first;
    
            if ( std::addressof(child.second) == std::addressof(needle) 
              || find_subtree_helper(child.second, needle, next))
            {
                path = next;
                return true;
            }
        }
    
        return false;
    }
    
    path_type find_subtree(ptree const& haystack, ptree const& needle) {
        path_type path;
    
        if (!find_subtree_helper(haystack, needle, path))
            throw std::range_error("not subtree");
    
        return path;
    }
    

    Use it like:

    Live On Coliru

    path_type p = find_subtree(pt_b, pt_e1);
    std::cout << p.dump() << std::endl;
    

    Which prints "c2.e1".

    Full Listing

    Live On Coliru

    #include <iostream>
    #include <boost/property_tree/ptree.hpp>
    #include <boost/property_tree/json_parser.hpp>
    
    using namespace boost::property_tree;
    
    using path_type = ptree::path_type;
    
    bool find_subtree_helper(ptree const& haystack, ptree const& needle, path_type& path) {
        if (std::addressof(haystack) == std::addressof(needle))
            return true;
    
        for (auto& child : haystack) {
            auto next = path;
            next /= child.first;
    
            if ( std::addressof(child.second) == std::addressof(needle) 
              || find_subtree_helper(child.second, needle, next))
            {
                path = next;
                return true;
            }
        }
    
        return false;
    }
    
    path_type find_subtree(ptree const& haystack, ptree const& needle) {
        path_type path;
    
        if (!find_subtree_helper(haystack, needle, path))
            throw std::range_error("not subtree");
    
        return path;
    }
    
    int main()
    {
        ptree pt0;
    
        pt0.put("a.b.c1",4);
        pt0.put("a.b.c2.e1",4);
        pt0.put("a.b.c4",4);
        pt0.put("a.d",4);
        pt0.put("k.m",4);
        pt0.put("k.n",4);
    
        ptree &pt_e1 = pt0.get_child("a.b.c2.e1");
        ptree &pt_b  = pt0.get_child("a.b");
    
        path_type p = find_subtree(pt_b, pt_e1);
        std::cout << p.dump() << std::endl;
    }