c++ 基於boost序列化XML

 與ajson庫用法類似

Example:

struct examle_struct
{
    int                _property_int;
    std::string        _property_str;
    std::string        value_str;
    bool               value_bool;
    int                value_int;
    std::vector<int>   value_vec;
}

AXML(examle_struct, (_property_int)(_property_str)(value_str)(value_bool)(value_int)(value_vec))


int main()
{
    //to xml
    std::istringstream iss;
    examle_struct exam;
    exam._property_int = 1;
    exam._property_str = "hello";
    exam.value_str = "world";
    exam.value_bool = false;
    exam.value_int = 10;
    exam.value_vec << 1 << 2 << 3;
    boost::axml::save(exam, "examle_struct", iss);
    std::cout << iss.str() << std::endl;

    //from xml
    std::string xml_str = iss.str();
    std::ostringstream oss(xml_str);
    examle_struct exam1;
    boost::axml::load(exam1,oss);

    return 0;
}

Src:

#pragma once
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <iostream>

#include <boost/cstdint.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/mpl/if.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/property_tree/detail/rapidxml.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/exception/diagnostic_information.hpp>

namespace boost
{
	namespace axml
	{
		using namespace boost::property_tree::detail::rapidxml;

		template <typename ty>
		struct node_support_read_impl
		{
			typedef ty value_type;
			typedef node_support_read_impl<ty> impl;
			static void read(xml_node<char>& xml_value, value_type& value) {}
		};

		template <typename ty>
		struct attribute_support_read_impl
		{
			typedef ty value_type;
			typedef attribute_support_read_impl<ty> impl;
			static void read(xml_attribute<char>& xml_value, value_type& value) {}
		};

		template <typename ty>
		struct node_support_write_impl
		{
			typedef ty value_type;
			typedef node_support_write_impl<ty> impl;
			static void write(std::ostream& stream, std::string name, const value_type& value) {}
		};

		template <typename ty>
		struct attribute_support_write_impl
		{
			typedef ty value_type;
			typedef attribute_support_write_impl<ty> impl;
			static void write(std::ostream& stream, std::string name, const value_type& value) {}
		};

// 		template <typename ty>
// 		struct node_support_read;
// 
// 		template <typename ty>
// 		struct attribute_support_read;
// 
// 		template <typename ty>
// 		struct value_support_write;
// 
// 		template <typename ty>
// 		struct attribute_support_write;

		template<typename ty>
		struct integer_arithmetic_support_read_impl
		{
			typedef ty value_type;
			static void read(xml_base<char>& xml_value, value_type& value)
			{
				std::string str_value(xml_value.value());
				if (str_value.empty())
				{
					value = 0;
					return;
				}
				value = boost::lexical_cast<value_type>(str_value);
			}
		};

		template<typename ty>
		struct integer_arithmetic_support_write_impl
		{
			typedef ty value_type;
			static void write(std::ostream& stream, std::string name, const value_type& value)
			{
				std::string buffer = boost::str(boost::format("%1%") % value);
				if (name[0] == '_')
				{
					std::string attr_name = name.substr(1);
					stream << boost::str(boost::format(" %s=%s") % attr_name %buffer);
				}
				else
				{
					stream << boost::str(boost::format("\n<%s>%s</%s>") % name %buffer %name);
				}
			}
		};

		template<typename ty>
		struct float_arithmetic_support_read_impl
		{
			typedef ty value_type;
			static void read(xml_base<char>& xml_value, value_type& value)
			{
				std::string str_value(xml_value.value());
				if (str_value.empty())
				{
					value = 0.0;
					return;
				}
				value = boost::lexical_cast<value_type>(str_value);
			}
		};

		template<typename ty>
		struct float_arithmetic_support_write_impl
		{
			typedef ty value_type;
			static void write(std::ostream& stream, std::string name, const value_type& value)
			{
				std::string str_value = boost::str(boost::format("%1%") % value);
				if (name[0] == '_')
				{
					std::string attr_name = name.substr(1);
					stream << boost::str(boost::format(" %s=%s") % attr_name %str_value);
				}
				else
				{
					stream << boost::str(boost::format("\n<%s>%s</%s>") % name %str_value %name);
				}
			}
		};

		template<>
		struct integer_arithmetic_support_read_impl <bool>
		{
			typedef bool value_type;
			static void read(xml_base<char>& xml_value, value_type& value)
			{
				std::string str_value(xml_value.value());
				if (str_value.empty())
				{
					value = 0;
					return;
				}
				if (str_value == "0" || str_value == "false")
				{
					value = 0;
					return;
				}
				value = 1;
			}
		};

		template<>
		struct integer_arithmetic_support_write_impl < bool >
		{
			typedef bool value_type;
			static void write(std::ostream& stream, std::string name, const value_type& value)
			{
				std::string str_value = (value ? "1" : "0");
				if (name[0] == '_')
				{
					std::string attr_name = name.substr(1);
					stream << boost::str(boost::format(" %s=%s") % attr_name %str_value);
				}
				else
				{
					stream << boost::str(boost::format("\n<%s>%s</%s>") % name %str_value %name);
				}
			}
		};

		template <typename ty>
		struct arithmetic_support_read_impl
		{
			typedef ty value_type;
			typedef typename ::boost::mpl::if_<
				::boost::is_integral<value_type>,
				integer_arithmetic_support_read_impl<value_type>,
				float_arithmetic_support_read_impl<value_type>
			>::type impl;
		};

		template <typename ty>
		struct arithmetic_support_write_impl
		{
			typedef ty value_type;
			typedef typename ::boost::mpl::if_<
				::boost::is_integral<value_type>,
				integer_arithmetic_support_write_impl<value_type>,
				float_arithmetic_support_write_impl<value_type>
			>::type impl;
		};

		template<typename ty>
		struct string_support_read_impl
		{
			typedef ty value_type;

			static void read(xml_base<char>& xml_value, value_type& value)
			{
				std::string str_value(xml_value.value());
				if (str_value.empty())
				{
					value = "";
					return;
				}
				value = str_value;
			}
		};

		template<typename ty>
		struct string_support_write_impl
		{
			typedef ty value_type;
			static void write(std::ostream& stream, std::string name, const value_type& value)
			{
				std::string str_value(value);
				if (name[0] == '_')
				{
					std::string attr_name = name.substr(1);
					stream << boost::str(boost::format(" %s=\"%s\"") % attr_name %str_value);
				}
				else
				{
					stream << boost::str(boost::format("\n<%s>%s</%s>") % name %str_value %name);
				}
			}
		};

		template<typename char_traits_ty, typename char_alloc_type>
		struct node_support_read_impl< ::std::basic_string<char, char_traits_ty, char_alloc_type>>
		{
			typedef ::std::basic_string<char, char_traits_ty, char_alloc_type> value_type;
			typedef  string_support_read_impl<value_type> impl;
		};

		template<typename char_traits_ty, typename char_alloc_type>
		struct attribute_support_read_impl< ::std::basic_string<char, char_traits_ty, char_alloc_type>>
		{
			typedef ::std::basic_string<char, char_traits_ty, char_alloc_type> value_type;
			typedef  string_support_read_impl<value_type> impl;
		};

		template<typename char_traits_ty, typename char_alloc_type>
		struct node_support_write_impl< ::std::basic_string<char, char_traits_ty, char_alloc_type>>
		{
			typedef ::std::basic_string<char, char_traits_ty, char_alloc_type> value_type;
			typedef  string_support_write_impl<value_type> impl;
		};

		template<typename char_traits_ty, typename char_alloc_type>
		struct attribute_support_write_impl< ::std::basic_string<char, char_traits_ty, char_alloc_type>>
		{
			typedef ::std::basic_string<char, char_traits_ty, char_alloc_type> value_type;
			typedef  string_support_write_impl<value_type> impl;
		};

		template<int N>
		struct char_array_support_read_impl
		{
			//typedef ty value_type;
			static void read(xml_node<char>& xml_value, char(&value)[N])
			{
				char * nv = xml_value.value();
				size_t nc = xml_value.value_size();
				size_t vc = N;
				for (size_t i = 0; i<nv && i<vc; ++i)
				{
					value[i] = nv[i];
				}
				if (vc > nc)
					value[nc] = 0;
			}
		};

		template<size_t N>
		struct char_array_support_write_impl
		{
			//typedef ty value_type;
			static inline void write(std::ostream& stream, std::string name, const char(&value)[N])
			{
				const char * str_value = value;
				stream << boost::str(boost::format("\n<%s>%s</%s>") % name %str_value %name);
			}
		};

		template<int N>
		struct node_support_read_impl< char[N]>
		{
			typedef char value_type[N];
			typedef  char_array_support_read_impl<N> impl;
		};

		template<int N>
		struct node_support_write_impl< char[N]>
		{
			typedef const char value_type[N];
			typedef  char_array_support_write_impl<N> impl;
		};


		template<typename ty>
		struct container_seq_support_read_impl
		{
			//typedef ty value_type;
			static void read(xml_node<char>& xml_value, ty& value)
			{
				value.clear();
				xml_node<char> *peer = &xml_value;
				while (peer)
				{
					typename ty::value_type item;
					node_support_read<typename ty::value_type>::impl::read(*peer, item);
					value.push_back(item);
					peer = peer->next_sibling(xml_value.name());
				}
			}
		};

		template<typename ty>
		struct container_seq_support_write_impl
		{
			typedef ty value_type;
			static void write(std::ostream& stream, std::string name, const value_type& value)
			{
				for (typename ty::const_iterator iter = value.cbegin(); iter != value.cend(); ++iter)
				{
					node_support_write<typename ty::value_type>::impl::write(stream, name, *iter);
				}
			}
		};

		template<typename ty, typename alloc_ty>
		struct node_support_read_impl< ::std::list<ty, alloc_ty>>
		{
			typedef typename ::std::list<ty, alloc_ty> value_type;
			typedef container_seq_support_read_impl<value_type> impl;
		};

		template<typename ty, typename alloc_ty>
		struct node_support_write_impl< ::std::list<ty, alloc_ty>>
		{
			typedef typename ::std::list<ty, alloc_ty> value_type;
			typedef container_seq_support_write_impl<value_type> impl;
		};

		template<typename ty, typename alloc_ty>
		struct node_support_read_impl< ::std::deque<ty, alloc_ty>>
		{
			typedef typename ::std::deque<ty, alloc_ty> value_type;
			typedef container_seq_support_read_impl<value_type> impl;
		};

		template<typename ty, typename alloc_ty>
		struct node_support_write_impl< ::std::deque<ty, alloc_ty>>
		{
			typedef typename ::std::deque<ty, alloc_ty> value_type;
			typedef container_seq_support_write_impl<value_type> impl;
		};

		template<typename ty, typename alloc_ty>
		struct node_support_read_impl< ::std::vector<ty, alloc_ty>>
		{
			typedef typename ::std::vector<ty, alloc_ty> value_type;
			typedef container_seq_support_read_impl<value_type> impl;
		};

		template<typename ty, typename alloc_ty>
		struct node_support_write_impl< ::std::vector<ty, alloc_ty>>
		{
			typedef typename ::std::vector<ty, alloc_ty> value_type;
			typedef container_seq_support_write_impl<value_type> impl;
		};


		template <typename ty>
		struct node_support_read
		{
			typedef typename ::boost::remove_const<ty>::type value_type;
			typedef typename ::boost::mpl::if_<
				::boost::is_arithmetic<value_type>,
				typename arithmetic_support_read_impl< value_type>::impl,
				typename node_support_read_impl<value_type>::impl
			>::type impl;
		};

		template <typename ty>
		struct attribute_support_read
		{
			typedef typename ::boost::remove_const<ty>::type value_type;
			typedef typename ::boost::mpl::if_<
				::boost::is_arithmetic<value_type>,
				typename arithmetic_support_read_impl< value_type>::impl,
				typename attribute_support_read_impl<value_type>::impl
			>::type impl;
		};

		template <typename ty>
		struct node_support_write
		{
			typedef typename ::boost::remove_const<ty>::type value_type;
			typedef typename ::boost::mpl::if_<
				::boost::is_arithmetic<value_type>,
				typename arithmetic_support_write_impl<value_type>::impl,
				typename node_support_write_impl<value_type>::impl
			>::type impl;
		};

		template <typename ty>
		struct attribute_support_write
		{
			typedef typename ::boost::remove_const<ty>::type value_type;
			typedef typename ::boost::mpl::if_<
				::boost::is_arithmetic<value_type>,
				typename arithmetic_support_write_impl<value_type>::impl,
				typename attribute_support_write_impl<value_type>::impl
			>::type impl;
		};

		template<typename ty>
		void axml_read_node(xml_node<char>& xml_value, ty& value)
		{
			node_support_read<ty>::impl::read(xml_value, value);
		}

		template<typename ty>
		void axml_read_attribute(xml_attribute<char>& xml_value, ty& value)
		{
			attribute_support_read<ty>::impl::read(xml_value, value);
		}

		template< typename ty>
		void axml_write_node(std::ostream& stream, std::string name, ty& value)
		{
			node_support_write<ty>::impl::write(stream, name, value);
		}

		template< typename ty>
		void axml_write_attribute(std::ostream& stream, std::string name, ty& value)
		{
			attribute_support_write<ty>::impl::write(stream, name, value);
		}

		template<typename ty>
		inline bool load_from_node(ty& value, const xml_node<char>& node)
		{
			return axml_read_node(node, value);
		}


		template<typename ty>
		inline void load(ty& value, std::istream& stream)
		{
			xml_document<char> document;
			// Load data into vector
			stream.unsetf(std::ios::skipws);
			std::vector<char> v(std::istreambuf_iterator<char>(stream.rdbuf()),
				std::istreambuf_iterator<char>());
			if (!stream.good() || v.empty())
			{
				document.clear();
				throw std::exception("read xml error");
			}
			v.push_back(0); // zero-terminate

			try 
			{
				document.parse<0>(&v.front());
				xml_node<char>* root_node = document.first_node();
				axml_read_node(*root_node, value);
			}
			catch(...)
			{
				document.clear();
				throw;
			}
			document.clear();
		}

		template<typename ty>
		inline void save(ty& value, std::string root_name, std::ostream& stream)
		{
			
			stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
			axml_write_node(stream, root_name, value);
			stream.flush();
			if (!stream)
			{
				throw std::exception("write error");
			}
		}
	}
}

#ifndef AXML

#define AXML_READ_MEMBER( r , v , elem ) \
	member_name = BOOST_DO_STRINGIZE(elem);\
	if (member_name[0] == '_')\
	{\
		xml_attribute<char>* attr = xml_value.first_attribute(member_name + 1);\
		if (attr) {axml_read_attribute(*attr, value.elem);}\
	}\
	else\
	{\
		xml_node<char>* node = xml_value.first_node(member_name);\
		if (node){axml_read_node(*node , value.elem);}\
	}

#define AXML_WRITE_MEMBER( r ,v , elem ) \
	member_name = BOOST_DO_STRINGIZE(elem);\
	if (member_name[0] != '_')\
	{\
		axml_write_node(stream, member_name, value.elem); \
	}

#define AXML_WRITE_ATTR( r ,v , elem ) \
	member_name = BOOST_DO_STRINGIZE(elem);\
	if (member_name[0] == '_')\
	{\
		axml_write_attribute(stream, member_name, value.elem); \
	}



#define AXML(TYPE, MEMBERS)\
namespace boost\
{\
	namespace axml\
	{\
		template <>\
		struct node_support_read_impl<TYPE>\
		{\
			typedef TYPE value_type;\
			typedef node_support_read_impl<TYPE> impl;\
			static inline void read(const xml_node<char>& xml_value , value_type& value)\
			{\
				char * member_name = NULL;\
				BOOST_PP_SEQ_FOR_EACH( AXML_READ_MEMBER , 0 , MEMBERS ) \
				return;\
			}\
		};\
		template <>\
		struct node_support_write_impl<TYPE>\
		{\
			typedef TYPE value_type;	\
			typedef node_support_write_impl<TYPE> impl;\
			static inline void write(std::ostream& stream, std::string name, const value_type& value)\
			{\
				stream << "\n<" << name;\
				char * member_name = NULL;\
				BOOST_PP_SEQ_FOR_EACH( AXML_WRITE_ATTR , 0 , MEMBERS ) \
				stream << ">";\
				BOOST_PP_SEQ_FOR_EACH( AXML_WRITE_MEMBER , 0 , MEMBERS ) \
				stream << "\n</" << name << ">";\
				return;\
			}\
		};\
	}\
}
#endif

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章