Boost :: property_tree:使用std :: vector<>在XML解析器中将多个值存储在一个键中 [英] Boost::property_tree: Using std::vector<> in XML parser to store multiple values in one key

查看:106
本文介绍了Boost :: property_tree:使用std :: vector<>在XML解析器中将多个值存储在一个键中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与此问题有关: Boost property_tree:每个键有多个值,然后回答该问题:提升property_tree:在模板类上,每个键都有多个值

My question is related to this question: Boost property_tree: multiple values per key and to a question following that question: Boost property_tree: multiple values per key, on a template class.

我正在尝试解析一个XML文件,该文件中多个值列在使用 std :: vector<> 的单个键值。到目前为止,我已经实现了以下代码:

I am trying to parse an XML file in which multiple values are listed at a single key value using std::vector<>. The following code is what I have implemented so far:

#include <boost/optional.hpp>
#include <boost/property_tree/xml_parser.hpp>

namespace boost { namespace property_tree
{

template<typename type>
struct vector_xml_translator
{
    boost::optional<std::vector<type> > get_value(const std::string& str)
    {
        if (!str.empty())
        {
            std::vector<type> values;
            std::stringstream ss(str);

            while (ss)
            {
                type temp_value;
                ss >> temp_value;
                values.push_back(temp_value);
            }

            return boost::optional<std::vector<type> >(values);
        }
        else
        {
            return boost::optional<std::vector<type> >(boost::none);
        }
    }

    boost::optional<std::string> put_value(const std::vector<type>& b)
    {
        std::stringstream ss;
        for (unsigned int i = 0; i < b.size(); i++)
        {
            ss << b[i];
            if (i != b.size()-1)
            {
                ss << " ";
            }
        }
        return boost::optional<std::string>(ss.str());
    }
};

template<typename ch, typename traits, typename alloc, typename data_type>
struct translator_between<std::basic_string<ch, traits, alloc>, std::vector<data_type> >
{
    typedef vector_xml_translator<data_type> type;
};

} // namespace property_tree
} // namespace boost

测试该代码的最小示例如下:

A minimal example to test this code is as follows:

#include <fstream>
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <XML_Vector_Translator.hpp>


int main()
{
    using boost::property_tree::ptree;

    std::vector<double> test_vector;

    test_vector.push_back(1);
    test_vector.push_back(6);
    test_vector.push_back(3);


    ptree pt;
    pt.add("base", test_vector);

    std::ofstream os("test_file.xml");

    write_xml(os, pt, boost::property_tree::xml_writer_settings<std::string>(' ', 2));

    std::ifstream is("test_file.xml");

    ptree pt_2;
    read_xml(is, pt_2);

    std::vector<int> test_vector_2;

    test_vector_2 = pt_2.get<std::vector<int> >("base");

    for (unsigned int i = 0; i < test_vector_2.size(); i++)
    {
        std::cout << test_vector_2[i] << std::endl;
    }

    return 0;
}

当我运行这段代码时,我得到了很多错误,这导致我认为翻译器结构的注册不正确。有人知道如何解决此问题和/或改进此代码吗?

When I run this code I get a number of errors, which lead me to believe that the registration of the translator structure is not right. Does anybody have an idea of how to solve this issue and/or improve this code?

推荐答案


  1. 正如较早的答案所指出的那样,您必须满足 boost :: property_tree :: detail :: is_translator 的要求,因此您需要 internal_type / external_type typedefs。

  1. As the older answer also points out¹ you must satisfy the requirements for boost::property_tree::detail::is_translator, so you need the internal_type / external_type typedefs.

typedef T internal_type;
typedef T external_type;


  • 接下来,循环是错误的,您需要检查值提取的结果:

  • Next up, the loop is wrong, you need check the result of the value extraction:

    while (ss >> temp_value)
        values.push_back(temp_value);
    


  • 将自己的类型放在boost名称空间中是一种不好的做法。仅需要 translator_between<> 的专业化即可。

    您可以简化和概括很多代码

    You can simplify and generalize a lot of the code

    全部在工作的演示中:

    在Coliru上直播

    #include <boost/optional.hpp>
    #include <boost/property_tree/ptree.hpp>
    #include <vector>
    #include <list>
    
    namespace mylib { namespace xml_translators {
    
        template<typename T> struct container
        {
            // types
            typedef T internal_type;
            typedef T external_type;
    
            boost::optional<T> get_value(const std::string& str) const
            {
                if (str.empty())
                    return boost::none;
    
                T values;
                std::stringstream ss(str);
    
                typename T::value_type temp_value;
                while (ss >> temp_value)
                    values.insert(values.end(), temp_value);
    
                return boost::make_optional(values);
            }
    
            boost::optional<std::string> put_value(const T& b) {
                std::stringstream ss;
                size_t i = 0;
                for (auto v : b)
                    ss << (i++?" ":"") << v;
                return ss.str();
            }
        };
    
    } }
    
    namespace boost { namespace property_tree {
        template<typename ch, typename traits, typename alloc, typename T>
            struct translator_between<std::basic_string<ch, traits, alloc>, std::vector<T> > {
                typedef mylib::xml_translators::container<std::vector<T> > type;
            };
    
        template<typename ch, typename traits, typename alloc, typename T>
            struct translator_between<std::basic_string<ch, traits, alloc>, std::list<T> > {
                typedef mylib::xml_translators::container<std::list<T> > type;
            };
    } }
    
    #include <sstream>
    #include <iostream>
    #include <boost/property_tree/xml_parser.hpp>
    
    int main()
    {
        std::stringstream ss;
        using boost::property_tree::ptree;
    
        {
            ptree pt;
            pt.add("base", std::vector<double> { 1, 6, 3 });
    
            write_xml(ss, pt, boost::property_tree::xml_writer_settings<std::string>(' ', 2));
        }
    
        {
            ptree pt;
            read_xml(ss, pt);
    
            std::cout << "As string: '" << pt.get("base", "") << "'\n";
            auto roundtrip = pt.get<std::list<int> >("base");
            for (auto i : roundtrip)
                std::cout << i << std::endl;
        }
    }
    

    打印

    As string: '1 6 3'
    1
    6
    3
    

    ¹提升property_tree:每个键有多个值,另请参见身份翻译器 http://www.boost.org/doc/libs/1_64_0/doc/html/boost/property_tree/id_translator.html

    ¹ Boost property_tree: multiple values per key, see also the identity translator http://www.boost.org/doc/libs/1_64_0/doc/html/boost/property_tree/id_translator.html

    这篇关于Boost :: property_tree:使用std :: vector&lt;&gt;在XML解析器中将多个值存储在一个键中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆