Search code examples
c++boostboost-propertytree

Property tree: complete path and name


I'd like to create a class that can be constructed from a property tree, as in this example:

<?xml version="1.0" encoding="utf-8"?>
<config>
    <name>testing</name>
    <!-- Test property tree -->
    <lambda min="200000" max="200">100</lambda>
...

That is easy with a property tree, but then I need to access two properties of a subtree, as in this class:

parameter::parameter(boost::property_tree::ptree t)
{
    // Set the value
    value = t.get_value<double>();

    // ?????
    auto nodename = t.something();

    // ?????
    std::string nodepath = t.somethingelse();

    // Get the attributes (or empty)
    auto p = t.get_child("<xmlattr>", boost::property_tree::ptree());

    // If we have attributes, read them
    if (p != boost::property_tree::ptree())
    {
        min = t.get<double>("<xmlattr>.min");
        max = t.get<double>("<xmlattr>.max");

        if (min > max)
            throw std::runtime_error("Min and max values invalid for the parameter " + nodename + ", path: " + nodepath);
    }
    else
    {
        min = +1.0;
        max = -1.0;
    }
}

// ... Someplace else
lambda = parameter(config.get_child("config.lambda"));

In the XML the mim/max attributes for lambda are invalid, and I need to throw an exception that could be read as

Min and max values invalid for the parameter lambda, path: config.lambda

Of course I could just pass the string, but it would defat the purpose. I've tried messing around t's iterator and data, but got nothing.

Can I obtain those values from a ptree?

Thanks!


Solution

  • I'd slightly shuffle the interface around so you don't drop the information you need prematurely:

    Live On Coliru

    #include <boost/property_tree/xml_parser.hpp>
    
    using boost::property_tree::ptree;
    
    struct parameter {
        parameter(ptree const& tree, ptree::path_type const& nodepath)
        {
            ptree const& t = tree.get_child(nodepath);
            // Set the value
            value = t.get_value<double>();
    
            auto nodename = [nodepath] {
                auto copy = nodepath;
                while (!copy.single()) copy.reduce();
                return copy.reduce();
            }();
    
            // Get the attributes (or empty)
            auto p = t.get_child("<xmlattr>", boost::property_tree::ptree());
    
            // If we have attributes, read them
            if (p != boost::property_tree::ptree())
            {
                auto min = t.get<double>("<xmlattr>.min");
                auto max = t.get<double>("<xmlattr>.max");
    
                if (min > max)
                    throw std::runtime_error("Min and max values invalid for the parameter " + nodename + ", path: " + nodepath.dump());
            }
            else
            {
                min = +1.0;
                max = -1.0;
            }
        }
    
      private:
        double min, max;
        double value;
    };
    
    int main() {
        ptree config;
        std::ifstream xml("input.txt");
        read_xml(xml, config);
    
        auto lambda = parameter(config, "config.lambda");
    }
    

    Prints

    terminate called after throwing an instance of 'std::runtime_error'
      what():  Min and max values invalid for the parameter lambda, path: config.lambda