2017-05-03 74 views
2

我的问题与此问题有关:Boost property_tree: multiple values per key并针对该问题后面的问题:Boost property_tree: multiple values per key, on a template classBoost :: property_tree:在XML解析器中使用std :: vector <>将多个值存储在一个密钥中

我想解析一个XML文件,其中多个值使用std::vector<>在单个键值处列出。下面的代码是我迄今实施:

#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 

小例子来测试这个代码如下:

#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; 
} 

当我运行这段代码,我得到了一些错误,从而导致我相信翻译结构的注册是不正确的。有没有人知道如何解决这个问题和/或改进这些代码?

回答

1
  1. 由于上了年纪的答案点out¹必须满足boost::property_tree::detail::is_translator的要求,所以你需要internal_type/external_type的typedef。

    typedef T internal_type; 
    typedef T external_type; 
    
  2. 接下来,循环是错误的,你需要检查值提取的结果:

    while (ss >> temp_value) 
        values.push_back(temp_value); 
    
  3. 这是不好的做法,把自己的类型升压命名空间中。只有专业translator_between<>需要在那里。

  4. 可以简化和推广了很多代码

所有的工作演示的:

Live On 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 

¹Boost property_tree: multiple values per key,又见身份转换http://www.boost.org/doc/libs/1_64_0/doc/html/boost/property_tree/id_translator.html

+0

感谢这个非常明确和有用的答案 – Sjonnie

+0

Graag gedaan。 Blij dat het hielp! – sehe

相关问题