Search code examples
c++booststl

Extracting STL Map from Boost Property Tree


I understand that boost::property_tree::ptree may contain key-value pairs where the 'value' may be of any type. Now my question is that, now my 'value' is a std::map, and when I attempt to pt.get<std::map<std::string, std::string>> where pt is a property tree, I get a compile time error. Hence, my question is:

How to extract a STL map value from a boost property tree? If this is not possible, is there any way of converting between STL map and boost property tree (so that each node of the property tree is not a STL container but a simple data type).


Solution

  • Very simply:

    Live On Coliru

    ptree pt;
    
    std::map<std::string, ptree> m(pt.begin(), pt.end());
    

    However, note that keys need not be unique:

    std::multimap<std::string, ptree> mm(pt.begin(), pt.end());
    

    And if you are want to transform all values to std::string (assuming they all have a string value):

    std::map<std::string, std::string> dict;
    for (auto& [k,v]: pt) {
        dict.emplace(k, v.get_value<std::string>());
    }
    

    Side-By-Side Comparisoon

    Live On Compiler Explorer

    #include <boost/property_tree/ptree.hpp>
    #include <map>
    #include <fmt/ranges.h>
    using boost::property_tree::ptree;
    
    template<> struct fmt::formatter<ptree> : fmt::formatter<std::string>
    {
        template<typename Ctx>
        auto format(ptree const& pt, Ctx& ctx) {
            return format_to(ctx.out(), "'{}'", pt.get_value<std::string>());
        }
    };
    
    int main() {
        ptree pt;
        pt.put("keyA", "valueA-1");
        pt.put("keyB", "valueB");
        pt.put("keyC", "valueC");
    
        pt.add("keyA", "valueA-2"); // not replacing same key
        
        std::map<std::string, ptree> m(pt.begin(), pt.end());
        std::multimap<std::string, ptree> mm(pt.begin(), pt.end());
    
        std::map<std::string, std::string> dict;
        for (auto& [k,v]: pt) {
            dict.emplace(k, v.get_value<std::string>());
        }
    
        fmt::print(
            "map:\n\t{}\n"
            "multimap:\n\t{}\n"
            "dict:\n\t{}\n",
            fmt::join(m, "\n\t"),
            fmt::join(mm, "\n\t"),
            fmt::join(dict, "\n\t")
        );
    }
    

    Prints

    map: 
            ("keyA", 'valueA-1')
            ("keyB", 'valueB')
            ("keyC", 'valueC')
    multimap:
            ("keyA", 'valueA-1')
            ("keyA", 'valueA-2')
            ("keyB", 'valueB')
            ("keyC", 'valueC')
    dict:
            ("keyA", "valueA-1")
            ("keyB", "valueB")
            ("keyC", "valueC")
    

    BONUS: Ptree From String Dictionary

    added ptree_from_map function

    template <typename MapLike>
    ptree ptree_from_map(MapLike const& m) {
        ptree pt;
        for (auto const& [k,v]: m) {
            pt.add(k, v);
        }
        return pt;
    }