使用boost :: property_tree从XML解析十六进制数和十进制数

时间:2016-06-16 20:12:09

标签: c++ boost-propertytree

我正在使用boost::property_tree解析XML文件。我需要解析的数据包括常规十进制数,例如42和十六进制数字,例如0xF1。例如:

<hex>0xF1</hex>
<dec>42</dec>

分析十进制数并使用int将其转换为ptree::get<int>()很容易。但是,对十六进制数的相同调用失败。

我可以通过将十六进制数解析为std::string,然后使用std::istringstreamstd::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::string std::istringstreamstd::hex或{{std::octstd::dec转换为数字的方式1}? documentation显示有一个stream_translator.hpp标头文件看起来很有希望这样做 - 但是在Boost网站或标题中没有太多关于此文件的文档文件本身。使用std::istringstream的变通方法是可以接受的,但stream_translator.hpp让我想知道boost::property_tree是否提供了执行此操作的方法。

我需要能够轻松地在解析十六进制和十进制数字之间切换,就像在iss >> std::hex上使用iss >> std::decstd::istringstream iss一样容易。

(如果重要的话,我的编译器是VS2005。是的,&#39; 05不是&#39; 15。)

2 个答案:

答案 0 :(得分:1)

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;

答案 1 :(得分:0)

只需使用新的stoi/stol/stoll 并将其“基数”设置为0,它将自动检测数字基数。