解析 XML 和 boost::property_tree 中的十六进制数和十进制数
Parse hex numbers along with decimal numbers from XML with boost::property_tree
我正在用 boost::property_tree
解析 XML 文件。我需要解析的数据包括 42
等常规十进制数和 0xF1
等十六进制数。例如:
<hex>0xF1</hex>
<dec>42</dec>
解析十进制数并将它们转换为 int
和 ptree::get<int>()
很容易。但是,对十六进制数的相同调用失败了。
我可以通过将十六进制数解析为 std::string
然后使用 std::istringstream
和 std::hex
将其转换为 int
来解决这个问题。用代码演示:
#include <iostream>
#include <string>
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
using std::string;
namespace pt = boost::property_tree;
int main() {
pt::ptree tree;
try {
pt::read_xml("debug.xml", tree, pt::xml_parser::no_comments);
} catch (const pt::xml_parser_error&) {}
int hexnum;
// Doesn't work (throws exception)
try {
hexnum = tree.get<int>("hex");
} catch (const pt::ptree_bad_data&) {
std::cout << "caught bad ptree data exception";
}
// Workaround: parse as a string, then convert the string
string hexstring;
try {
hexstring = tree.get<string>("hex");
std::istringstream iss(hexstring);
iss >> std::hex >> hexnum;
if (!iss) throw std::ios_base::failure("invalid hex string");
} catch (const pt::ptree_error&) {
// get() failed
} catch (const std::ios_base::failure& fail) {
std::cout << fail.what();
}
// Parsing a regular decimal number is straightforward
int decnum;
try {
decnum = tree.get<int>("dec");
} catch (const pt::ptree_error&) {}
return 0;
}
有没有更优雅的方法来做到这一点,类似于我如何使用 std::istringstream
和 std::hex
、std::oct
或 std::oct
将 std::string
转换为数字std::dec
? documentation 显示有一个 stream_translator.hpp
头文件,它看起来很有希望作为执行此操作的一种方式——但在 Boost 网站或头文件本身中没有太多关于此文件的文档。 std::istringstream
的解决方法是可以接受的,但是 stream_translator.hpp
让我想知道 boost::property_tree
是否提供了一种方法来做到这一点。
我需要能够在解析十六进制和十进制数字之间轻松切换,就像在 std::istringstream iss
上使用 iss >> std::hex
或 iss >> std::dec
一样容易。
(以防万一,我的编译器是 VS2005。是的,'05 不是 '15。)
stream_translator的代码看起来很简单:它只有两个方法。我想你可以编写自己的翻译器并设置一个十六进制标志。像这样:
/// Implementation of Translator that uses the stream overloads.
template <typename Ch, typename Traits, typename Alloc, typename E>
class stream_translator
{
typedef customize_stream<Ch, Traits, E> customized;
public:
typedef std::basic_string<Ch, Traits, Alloc> internal_type;
typedef E external_type;
explicit stream_translator(std::locale loc = std::locale())
: m_loc(loc)
{}
boost::optional<E> get_value(const internal_type &v) {
std::basic_istringstream<Ch, Traits, Alloc> iss(v);
iss.imbue(m_loc);
iss.setf(std::ios_base::hex, std::ios_base::basefield);
E e;
customized::extract(iss, e);
if(iss.fail() || iss.bad() || iss.get() != Traits::eof()) {
return boost::optional<E>();
}
return e;
}
boost::optional<internal_type> put_value(const E &v) {
std::basic_ostringstream<Ch, Traits, Alloc> oss;
oss.imbue(m_loc);
oss.setf(std::ios_base::hex, std::ios_base::basefield);
customized::insert(oss, v);
if(oss) {
return oss.str();
}
return boost::optional<internal_type>();
}
private:
std::locale m_loc;
};
ptree 本身有 get
接受翻译器的方法。所以你可以把你自己的翻译器传到那里。
template<class Type, class Translator>
Type get(const path_type &path,
const Type &default_value,
Translator tr) const;
只需使用新的 stoi
/stol
/stoll
将其 "base" 设置为 0
,这将自动检测数字基数。
我正在用 boost::property_tree
解析 XML 文件。我需要解析的数据包括 42
等常规十进制数和 0xF1
等十六进制数。例如:
<hex>0xF1</hex>
<dec>42</dec>
解析十进制数并将它们转换为 int
和 ptree::get<int>()
很容易。但是,对十六进制数的相同调用失败了。
我可以通过将十六进制数解析为 std::string
然后使用 std::istringstream
和 std::hex
将其转换为 int
来解决这个问题。用代码演示:
#include <iostream>
#include <string>
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
using std::string;
namespace pt = boost::property_tree;
int main() {
pt::ptree tree;
try {
pt::read_xml("debug.xml", tree, pt::xml_parser::no_comments);
} catch (const pt::xml_parser_error&) {}
int hexnum;
// Doesn't work (throws exception)
try {
hexnum = tree.get<int>("hex");
} catch (const pt::ptree_bad_data&) {
std::cout << "caught bad ptree data exception";
}
// Workaround: parse as a string, then convert the string
string hexstring;
try {
hexstring = tree.get<string>("hex");
std::istringstream iss(hexstring);
iss >> std::hex >> hexnum;
if (!iss) throw std::ios_base::failure("invalid hex string");
} catch (const pt::ptree_error&) {
// get() failed
} catch (const std::ios_base::failure& fail) {
std::cout << fail.what();
}
// Parsing a regular decimal number is straightforward
int decnum;
try {
decnum = tree.get<int>("dec");
} catch (const pt::ptree_error&) {}
return 0;
}
有没有更优雅的方法来做到这一点,类似于我如何使用 std::istringstream
和 std::hex
、std::oct
或 std::oct
将 std::string
转换为数字std::dec
? documentation 显示有一个 stream_translator.hpp
头文件,它看起来很有希望作为执行此操作的一种方式——但在 Boost 网站或头文件本身中没有太多关于此文件的文档。 std::istringstream
的解决方法是可以接受的,但是 stream_translator.hpp
让我想知道 boost::property_tree
是否提供了一种方法来做到这一点。
我需要能够在解析十六进制和十进制数字之间轻松切换,就像在 std::istringstream iss
上使用 iss >> std::hex
或 iss >> std::dec
一样容易。
(以防万一,我的编译器是 VS2005。是的,'05 不是 '15。)
stream_translator的代码看起来很简单:它只有两个方法。我想你可以编写自己的翻译器并设置一个十六进制标志。像这样:
/// Implementation of Translator that uses the stream overloads.
template <typename Ch, typename Traits, typename Alloc, typename E>
class stream_translator
{
typedef customize_stream<Ch, Traits, E> customized;
public:
typedef std::basic_string<Ch, Traits, Alloc> internal_type;
typedef E external_type;
explicit stream_translator(std::locale loc = std::locale())
: m_loc(loc)
{}
boost::optional<E> get_value(const internal_type &v) {
std::basic_istringstream<Ch, Traits, Alloc> iss(v);
iss.imbue(m_loc);
iss.setf(std::ios_base::hex, std::ios_base::basefield);
E e;
customized::extract(iss, e);
if(iss.fail() || iss.bad() || iss.get() != Traits::eof()) {
return boost::optional<E>();
}
return e;
}
boost::optional<internal_type> put_value(const E &v) {
std::basic_ostringstream<Ch, Traits, Alloc> oss;
oss.imbue(m_loc);
oss.setf(std::ios_base::hex, std::ios_base::basefield);
customized::insert(oss, v);
if(oss) {
return oss.str();
}
return boost::optional<internal_type>();
}
private:
std::locale m_loc;
};
ptree 本身有 get
接受翻译器的方法。所以你可以把你自己的翻译器传到那里。
template<class Type, class Translator>
Type get(const path_type &path,
const Type &default_value,
Translator tr) const;
只需使用新的 stoi
/stol
/stoll
将其 "base" 设置为 0
,这将自动检测数字基数。