Boost property tree specify allowed values

半世苍凉 提交于 2019-12-11 09:39:44

问题


I wanted to use boosts property tree as handling the settings of my c++ app since it seems to be widely used in this scenario.

My question: when changing values in the property tree (through xml parsing or manually), is there a way to specify a list of allowed values of a key in advance? E.g. if I wanted to do a simple "Yes/No" setting, do I have to check the values with an if - condition or can I somehow teach my tree to only accept the two values "Yes" and "No" for the specific key in advance, so that it throws an exception on error.


回答1:


You can use translators for this. A nice blog post I remember that describes this to get custom date format parsing in an XML-backed property tree was here:

  • Andzrej's blog

Let's take your example:

enum class YesNo { No, Yes };

In this case the calling code could look like:

static YesNoTranslator trans;

int main() {

    std::istringstream iss(R"(
            <?xml version="1.0"?>
            <demo>
                <positive>Yes</positive>
                <negative>No</negative>
                <invalid>Bogus</invalid>
            </demo>
        )");

    ptree pt;
    read_xml(iss, pt);


    for (auto&& field : { "demo.positive", "demo.negative", "demo.invalid" })
    {
        try {
            std::cout << "With 'No' default: '" << field << "':\t" << pt.get(field, YesNo::No, trans) << "\n";
            std::cout << "Without default:   '" << field << "':\t" << pt.get<YesNo>(field, trans)     << "\n";
        } catch(std::exception const& e) {
            std::cout << "Error parsing '"      << field << "':\t" << e.what()                        << "\n";
        }
    }
}

Full Demo

Live On Coliru

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <sstream>
#include <iostream>

using boost::property_tree::ptree;

enum class YesNo { No, Yes };

static inline std::ostream& operator<<(std::ostream& os, YesNo v) {
    switch(v) {
        case YesNo::Yes: return os << "Yes";
        case YesNo::No:  return os << "No";
    }
    return os << "??";
}

struct YesNoTranslator {
    typedef std::string  internal_type;
    typedef YesNo        external_type;

    boost::optional<external_type> get_value(internal_type const& v) {
        if (v == "Yes") return YesNo::Yes;
        if (v == "No")  return YesNo::No;

        return boost::none;
    }

    boost::optional<internal_type> put_value(external_type const& v) {
        switch(v) {
            case YesNo::Yes: return std::string("Yes");
            case YesNo::No:  return std::string("No");
            default: throw std::domain_error("YesNo");
        }
    }
};

static YesNoTranslator trans;

int main() {

    std::istringstream iss(R"(
            <?xml version="1.0"?>
            <demo>
                <positive>Yes</positive>
                <negative>No</negative>
                <invalid>Bogus</invalid>
            </demo>
        )");

    ptree pt;
    read_xml(iss, pt);


    for (auto&& field : { "demo.positive", "demo.negative", "demo.invalid" })
    {
        try {
            std::cout << "With 'No' default: '" << field << "':\t" << pt.get(field, YesNo::No, trans) << "\n";
            std::cout << "Without default:   '" << field << "':\t" << pt.get<YesNo>(field, trans)     << "\n";
        } catch(std::exception const& e) {
            std::cout << "Error parsing '"      << field << "':\t" << e.what()                        << "\n";
        }
    }

}

Which prints

With 'No' default: 'demo.positive': Yes
Without default:   'demo.positive': Yes
With 'No' default: 'demo.negative': No
Without default:   'demo.negative': No
With 'No' default: 'demo.invalid':  No
Without default:   'demo.invalid':  Error parsing 'demo.invalid':   conversion of data to type "5YesNo" failed


来源:https://stackoverflow.com/questions/31277354/boost-property-tree-specify-allowed-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!