...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
This tutorial uses XML. Note that the library is not specifically bound to XML, and any other supported format (such as INI or JSON) could be used instead. XML was chosen because the author thinks that a wide range of people is familiar with it.
Suppose we are writing a logging system for some application, and need to read log configuration from a file when the program starts. The file with the log configuration looks like this:
<debug> <filename>debug.log</filename> <modules> <module>Finance</module> <module>Admin</module> <module>HR</module> </modules> <level>2</level> </debug>
It contains the log filename, a list of modules where logging is enabled, and the debug level value.
First we need some includes:
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> #include <boost/foreach.hpp> #include <string> #include <set> #include <exception> #include <iostream> namespace pt = boost::property_tree;
To store the logging configuration in the program we create a debug_settings structure:
struct debug_settings { std::string m_file; // log filename int m_level; // debug level std::set<std::string> m_modules; // modules where logging is enabled void load(const std::string &filename); void save(const std::string &filename); };
All that needs to be done now is to write implementations of load() and save() member functions. Let's first deal with load(). It contains just 7 lines of code, although it does all the necessary things, including error reporting:
void debug_settings::load(const std::string &filename) { // Create empty property tree object pt::ptree tree; // Parse the XML into the property tree. pt::read_xml(filename, tree); // Use the throwing version of get to find the debug filename. // If the path cannot be resolved, an exception is thrown. m_file = tree.get<std::string>("debug.filename"); // Use the default-value version of get to find the debug level. // Note that the default value is used to deduce the target type. m_level = tree.get("debug.level", 0); // Use get_child to find the node containing the modules, and iterate over // its children. If the path cannot be resolved, get_child throws. // A C++11 for-range loop would also work. BOOST_FOREACH(pt::ptree::value_type &v, tree.get_child("debug.modules")) { // The data function is used to access the data stored in a node. m_modules.insert(v.second.data()); } }
Now the save() function. It is also 7 lines of code:
void debug_settings::save(const std::string &filename) { // Create an empty property tree object. pt::ptree tree; // Put the simple values into the tree. The integer is automatically // converted to a string. Note that the "debug" node is automatically // created if it doesn't exist. tree.put("debug.filename", m_file); tree.put("debug.level", m_level); // Add all the modules. Unlike put, which overwrites existing nodes, add // adds a new node at the lowest level, so the "modules" node will have // multiple "module" children. BOOST_FOREACH(const std::string &name, m_modules) tree.add("debug.modules.module", name); // Write property tree to XML file pt::write_xml(filename, tree); }
The full program debug_settings.cpp is included in the examples directory.