如何用boost::property_tree解析XML中带单位的std::chrono::duration字段?
如何用Boost.PropertyTree解析带单位的字符串到std::chrono::nanoseconds?
问题描述
我希望配置文件写成如下形式:
<?xml version="1.0" encoding="UTF-8"?> <Config> <DurationValue>20ns</DurationValue> </Config>
或者:
<?xml version="1.0" encoding="UTF-8"?> <Config> <DurationValue>15s</DurationValue> </Config>
需要统一解析DurationValue字段,最终存储为std::chrono::nanoseconds类型。我尝试的代码如下:
boost::property_tree::ptree property_tree; boost::property_tree::read_xml("config.xml", property_tree); auto config = property_tree.get_child("Config"); std::chrono::nanoseconds duration_value = std::chrono::duration_cast<std::chrono::nanoseconds>(config.get<std::common_type<std::chrono::duration>>("DurationValue"));
这段代码无法工作,因为Boost.PropertyTree不知道如何将字符串转换为std::chrono::duration类型。请问有没有可行的实现方式?希望能灵活支持任意std::chrono字面量对应的单位,感谢!
解决方案
Boost.PropertyTree本身没有内置对std::chrono::duration类型的序列化/反序列化支持,需要自定义解析逻辑。核心思路是先读取字符串值,再手动解析其中的数值和单位,转换为目标的nanoseconds类型。
步骤1:实现字符串到nanoseconds的解析函数
编写通用函数处理常见时间单位(ns、us、ms、s、min、h等):
#include <chrono> #include <string> #include <stdexcept> #include <cctype> std::chrono::nanoseconds parse_duration(const std::string& str) { // 定位单位起始位置(跳过数字和小数点) size_t unit_pos = str.find_first_not_of("0123456789."); if (unit_pos == std::string::npos) { throw std::invalid_argument("Invalid duration: missing time unit"); } // 拆分数值和单位 double value = std::stod(str.substr(0, unit_pos)); std::string unit = str.substr(unit_pos); // 转换为nanoseconds if (unit == "ns") { return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double, std::nano>(value)); } else if (unit == "us" || unit == "µs") { return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double, std::micro>(value)); } else if (unit == "ms") { return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double, std::milli>(value)); } else if (unit == "s") { return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double>(value)); } else if (unit == "min") { return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double, std::ratio<60>>(value)); } else if (unit == "h") { return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double, std::ratio<3600>>(value)); } else { throw std::invalid_argument("Unsupported time unit: " + unit); } }
步骤2:结合Boost.PropertyTree使用该函数
读取ptree中的字符串值,传入解析函数即可:
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> int main() { boost::property_tree::ptree property_tree; boost::property_tree::read_xml("config.xml", property_tree); auto config = property_tree.get_child("Config"); try { std::string duration_str = config.get<std::string>("DurationValue"); std::chrono::nanoseconds duration_value = parse_duration(duration_str); // 后续使用duration_value } catch (const std::exception& e) { // 处理解析失败的情况 std::cerr << "Failed to parse duration: " << e.what() << std::endl; } return 0; }
进阶:注册自定义转换器(可选)
如果希望直接用config.get<std::chrono::nanoseconds>("DurationValue")的方式,可以注册Boost.PropertyTree的自定义转换器:
#include <boost/property_tree/translator_between.hpp> namespace boost::property_tree { template <> struct translator_between<std::string, std::chrono::nanoseconds> { typedef translator_between<std::string, std::chrono::nanoseconds> type; std::chrono::nanoseconds get_value(const std::string& str) const { return parse_duration(str); } std::string put_value(const std::chrono::nanoseconds& dur) const { // 如需序列化,可在此实现反向转换(比如将nanoseconds转为带单位的字符串) return std::to_string(dur.count()) + "ns"; } }; }
注册后即可直接调用:
std::chrono::nanoseconds duration_value = config.get<std::chrono::nanoseconds>("DurationValue");
注意事项
- 解析函数支持浮点数和常见单位,如需支持更多单位(如天
d),可自行扩展分支。 - 建议添加异常捕获逻辑,处理无效数值、未知单位等错误场景。
内容的提问来源于stack exchange,提问作者SeedlessKiwi
相关产品推荐
相关产品推荐

