1

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!

senseiwa
  • 2,369
  • 3
  • 24
  • 47

1 Answers1

1

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
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks, @sehe. But is it possible to drop the path parameter? I'd like to retrieve, given a node, the path from the root. – senseiwa Sep 17 '16 at 05:51
  • I'm confused. What will you expect my answer to be? I mean, I'm able to read your question. (So, I did.) I'm not shuffling your code around because I have nothing better to do... – sehe Sep 17 '16 at 15:25
  • Sorry, I didn't mean to be rude. I am asking if there is a way. Your code works perfectly, I've used it. Maybe the right question is: is a ptree's path always relative to a node (it forgets the root), or is it absolute (it knows the root-to-node path)? – senseiwa Sep 18 '16 at 08:50
  • Better: a ptree node is just a ptree. It doesn't know about parents. It has no path. Paths are merely an addressing vector inside a ptree. – sehe Sep 18 '16 at 10:51