xml 与 protobuf之间的转换

这段代码展示了如何使用C++将TinyXML解析的XML数据转换为protobuf消息,以及将protobuf消息转换回XML。它利用了protobuf的反射API来处理各种字段类型,并支持不同的字符编码。
#ifndef _INTER_PROTO_TINYXML_H_
#define _INTER_PROTO_TINYXML_H_


#include <string>
#include "google/protobuf/message.h"


bool tinyxml2proto(const std::string& xml, google::protobuf::Message& msg);


enum tinyxml_type
{
	TINYXML_GB2312,
	TINYXML_UTF8,
};


bool proto2tinyxml(const google::protobuf::Message& msg, std::string& xml, tinyxml_type type = TINYXML_UTF8);


#endif //_INTER_PROTO_TINYXML_H_
#include "InterProtoTinyXml.h"
#include "tinyxml/tinyxml.h"
#include "google/protobuf/descriptor.h"
#include "utils/utils.h"

#define INTER_PROTO_TINYXML_NAME		"_name"
#define INTER_PROTO_TINYXML_VALUE		"_value"
#define INTER_PROTO_TINYXML_ATTR		"_attr_"
#define INTER_PROTO_TINYXML_ATTR_SIZE	6

using namespace google::protobuf;

template<class T>
static T get_xml_field(TiXmlNode* node, bool& get_ok)
{
	for(TiXmlNode* child_node = node->FirstChild(); child_node != NULL; child_node = node->NextSibling())
	{
		if(child_node->Type() == TiXmlNode::TINYXML_TEXT)
		{
			get_ok = true;
			return from_string<T>(string_trim(child_node->ValueStr(), " \r\n\t\""));
		}
	}

	get_ok = false;
	return T();
}

template<>
static std::string get_xml_field<std::string>(TiXmlNode* node, bool& get_ok)
{
	for(TiXmlNode* child_node = node->FirstChild(); child_node != NULL; child_node = node->NextSibling())
	{
		if(child_node->Type() == TiXmlNode::TINYXML_TEXT)
		{
			get_ok = true;
			return string_trim(child_node->ValueStr(), " \r\n\t\"");
		}
	}

	get_ok = false;
	return "";
}

template<>
static bool get_xml_field<bool>(TiXmlNode* node, bool& get_ok)
{
	for(TiXmlNode* child_node = node->FirstChild(); child_node != NULL; child_node = node->NextSibling())
	{
		if(child_node->Type() == TiXmlNode::TINYXML_TEXT)
		{
			get_ok = true;
			return (bool)from_string<int>(string_trim(child_node->ValueStr(), " \r\n\t\""));
		}
	}

	get_ok = false;
	return false;
}

static bool parse_xmlattr2proto(TiXmlElement* element, google::protobuf::Message& msg)
{
	if(!element)
	{
		assert(0);
		return false;
	}
	
	//解析XML文件
	const google::protobuf::Reflection* reflection = msg.GetReflection();
	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	for(TiXmlAttribute* attr = element->FirstAttribute(); attr != NULL; attr = attr->Next())
	{
		std::string name = attr->Name();
		std::string value = attr->Value();
		const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(INTER_PROTO_TINYXML_ATTR + name);
		if(fd)
		{
			switch(fd->type())
			{
				// double, exactly eight bytes on the wire.
			case FieldDescriptor::TYPE_DOUBLE:
				if(fd->is_repeated())
				{
					reflection->AddDouble(&msg, fd, from_string<double>(value));
				}
				else
				{
					reflection->SetDouble(&msg, fd, from_string<double>(value));
				}

				break;

				// float, exactly four bytes on the wire.
			case FieldDescriptor::TYPE_FLOAT:
				if(fd->is_repeated())
				{
					reflection->AddFloat(&msg, fd, from_string<float>(value));
				}
				else
				{
					reflection->SetFloat(&msg, fd, from_string<float>(value));
				}

				break;

				// int32, varint on the wire.  Negative numbers
				// take 10 bytes.  Use TYPE_SINT32 if negative
				// values are likely.
			case FieldDescriptor::TYPE_INT32:
				// int32, exactly four bytes on the wire
			case FieldDescriptor::TYPE_SFIXED32:
				// int32, ZigZag-encoded varint on the wire
			case FieldDescriptor::TYPE_SINT32:
				if(fd->is_repeated())
				{
					reflection->AddInt32(&msg, fd, from_string<google::protobuf::int32>(value));
				}
				else
				{
					reflection->SetInt32(&msg, fd, from_string<google::protobuf::int32>(value));
				}

				break;

				// uint32, varint on the wire
			case FieldDescriptor::TYPE_UINT32:
				// uint32, exactly four bytes on the wire.
			case FieldDescriptor::TYPE_FIXED32:
				if(fd->is_repeated())
				{
					reflection->AddUInt32(&msg, fd, from_string<google::protobuf::uint32>(value));
				}
				else
				{
					reflection->SetUInt32(&msg, fd, from_string<google::protobuf::uint32>(value));
				}

				break;

				// int64, varint on the wire.  Negative numbers
				// take 10 bytes.  Use TYPE_SINT64 if negative
				// values are likely.
			case FieldDescriptor::TYPE_INT64:
				// int64, exactly eight bytes on the wire
			case FieldDescriptor::TYPE_SFIXED64:
				// int64, ZigZag-encoded varint on the wire
			case FieldDescriptor::TYPE_SINT64:
				if(fd->is_repeated())
				{
					reflection->AddInt64(&msg, fd, from_string<google::protobuf::int64>(value));
				}
				else
				{
					reflection->SetInt64(&msg, fd, from_string<google::protobuf::int64>(value));
				}
				break;

				// uint64, varint on the wire.
			case FieldDescriptor::TYPE_UINT64:
				// uint64, exactly eight bytes on the wire.
			case FieldDescriptor::TYPE_FIXED64:
				if(fd->is_repeated())
				{
					reflection->AddUInt64(&msg, fd, from_string<google::protobuf::uint64>(value));
				}
				else
				{
					reflection->SetUInt64(&msg, fd, from_string<google::protobuf::uint64>(value));
				}

				break;

				// bool, varint on the wire.
			case FieldDescriptor::TYPE_BOOL:
				if(fd->is_repeated())
				{
					reflection->AddBool(&msg, fd, from_string<bool>(value));
				}
				else
				{
					reflection->SetBool(&msg, fd, from_string<bool>(value));
				}

				break;

				// UTF-8 text.
			case FieldDescriptor::TYPE_STRING:
				// Arbitrary byte array.
			case FieldDescriptor::TYPE_BYTES:
				if(fd->is_repeated())
				{
					reflection->AddString(&msg, fd, value);
				}
				else
				{
					reflection->SetString(&msg, fd, value);
				}

				break;

				// Tag-delimited message.  Deprecated.
			case FieldDescriptor::TYPE_GROUP:
				// Length-delimited message.
			case FieldDescriptor::TYPE_MESSAGE:
				assert(0);
				return false;
				break;

				// Enum, varint on the wire
			case FieldDescriptor::TYPE_ENUM:
				{
					const google::protobuf::EnumValueDescriptor* evd = fd->enum_type()->FindValueByNumber(from_string<int>(value));
					if(!evd)
					{
						return false;
					}

					if(fd->is_repeated())
					{
						reflection->AddEnum(&msg, fd, evd);
					}
					else
					{
						reflection->SetEnum(&msg, fd, evd);
					}
				}

				break;
			default:
				assert(0);
				return false;
				break;
			}
		}
	}

	return true;
}

static bool parse_xml2proto_msg(TiXmlNode* node, google::protobuf::Message& msg)
{
	assert(node && node->Type() == TiXmlNode::TINYXML_ELEMENT);
	//解析XML文件
	const google::protobuf::Reflection* reflection = msg.GetReflection();
	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	for(TiXmlNode* child_node = node->FirstChild(); child_node != NULL; child_node = child_node->NextSibling())
	{
		std::string child_value = child_node->ValueStr();
		switch(child_node->Type())
		{
		case TiXmlNode::TINYXML_ELEMENT:
			{
				const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(child_value);
				if(fd)
				{
					switch(fd->type())
					{
						// double, exactly eight bytes on the wire.
					case FieldDescriptor::TYPE_DOUBLE:
						{
							bool get_ok = false;
							double temp_value = get_xml_field<double>(child_node, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddDouble(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetDouble(&msg, fd, temp_value);
							}
						}
						
						break;

						// float, exactly four bytes on the wire.
					case FieldDescriptor::TYPE_FLOAT:
						{
							bool get_ok = false;
							float temp_value = get_xml_field<float>(child_node, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddFloat(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetFloat(&msg, fd, temp_value);
							}
						}
						break;

						// int32, varint on the wire.  Negative numbers
						// take 10 bytes.  Use TYPE_SINT32 if negative
						// values are likely.
					case FieldDescriptor::TYPE_INT32:
						// int32, exactly four bytes on the wire
					case FieldDescriptor::TYPE_SFIXED32:
						// int32, ZigZag-encoded varint on the wire
					case FieldDescriptor::TYPE_SINT32:
						{
							bool get_ok = false;
							google::protobuf::int32 temp_value = get_xml_field<google::protobuf::int32>(child_node, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddInt32(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetInt32(&msg, fd, temp_value);
							}
						}

						break;

						// uint32, varint on the wire
					case FieldDescriptor::TYPE_UINT32:
						// uint32, exactly four bytes on the wire.
					case FieldDescriptor::TYPE_FIXED32:
						{
							bool get_ok = false;
							google::protobuf::uint32 temp_value = get_xml_field<google::protobuf::uint32>(child_node, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddUInt32(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetUInt32(&msg, fd, temp_value);
							}
						}

						break;

						// int64, varint on the wire.  Negative numbers
						// take 10 bytes.  Use TYPE_SINT64 if negative
						// values are likely.
					case FieldDescriptor::TYPE_INT64:
						// int64, exactly eight bytes on the wire
					case FieldDescriptor::TYPE_SFIXED64:
						// int64, ZigZag-encoded varint on the wire
					case FieldDescriptor::TYPE_SINT64:
						{
							bool get_ok = false;
							google::protobuf::int64 temp_value = get_xml_field<google::protobuf::int64>(child_node, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddInt64(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetInt64(&msg, fd, temp_value);
							}
						}

						break;

						// uint64, varint on the wire.
					case FieldDescriptor::TYPE_UINT64:
						// uint64, exactly eight bytes on the wire.
					case FieldDescriptor::TYPE_FIXED64:
						{
							bool get_ok = false;
							google::protobuf::uint64 temp_value = get_xml_field<google::protobuf::uint64>(child_node, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddUInt64(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetUInt64(&msg, fd, temp_value);
							}
						}

						break;

						// bool, varint on the wire.
					case FieldDescriptor::TYPE_BOOL:
						{
							bool get_ok = false;
							bool temp_value = get_xml_field<bool>(child_node, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddBool(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetBool(&msg, fd, temp_value);
							}
						}

						break;

						// UTF-8 text.
					case FieldDescriptor::TYPE_STRING:
						// Arbitrary byte array.
					case FieldDescriptor::TYPE_BYTES:
						{
							bool get_ok = false;
							std::string temp_value = get_xml_field<std::string>(child_node, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddString(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetString(&msg, fd, temp_value);
							}
						}

						break;

						// Tag-delimited message.  Deprecated.
					case FieldDescriptor::TYPE_GROUP:
						// Length-delimited message.
					case FieldDescriptor::TYPE_MESSAGE:
						if(fd->is_repeated())
						{
							if(!parse_xml2proto_msg(child_node, *reflection->AddMessage(&msg, fd)))
							{
								return false;
							}
						}
						else
						{
							if(!parse_xml2proto_msg(child_node, *reflection->MutableMessage(&msg, fd)))
							{
								return false;
							}
						}

						break;

						// Enum, varint on the wire
					case FieldDescriptor::TYPE_ENUM:
						{
							bool get_ok = false;
							int temp_value = get_xml_field<int>(child_node, get_ok);
							if(!get_ok)
							{
								return false;
							}

							const google::protobuf::EnumValueDescriptor* evd = fd->enum_type()->FindValueByNumber(temp_value);
							if(!evd)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddEnum(&msg, fd, evd);
							}
							else
							{
								reflection->SetEnum(&msg, fd, evd);
							}
						}

						break;
					default:
						assert(0);
						return false;
						break;
					}
				}
			}

			break;
		case TiXmlNode::TINYXML_TEXT:
			{
				const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(INTER_PROTO_TINYXML_VALUE);
				if(fd)
				{
					child_value = string_trim(child_value, " \r\n\t\"");
					switch(fd->type())
					{
						// double, exactly eight bytes on the wire.
					case FieldDescriptor::TYPE_DOUBLE:
						if(fd->is_repeated())
						{
							reflection->AddDouble(&msg, fd, from_string<double>(child_value));
						}
						else
						{
							reflection->SetDouble(&msg, fd, from_string<double>(child_value));
						}

						break;

						// float, exactly four bytes on the wire.
					case FieldDescriptor::TYPE_FLOAT:
						if(fd->is_repeated())
						{
							reflection->AddFloat(&msg, fd, from_string<float>(child_value));
						}
						else
						{
							reflection->SetFloat(&msg, fd, from_string<float>(child_value));
						}

						break;
				
						// int32, varint on the wire.  Negative numbers
						// take 10 bytes.  Use TYPE_SINT32 if negative
						// values are likely.
					case FieldDescriptor::TYPE_INT32:
						// int32, exactly four bytes on the wire
					case FieldDescriptor::TYPE_SFIXED32:
						// int32, ZigZag-encoded varint on the wire
					case FieldDescriptor::TYPE_SINT32:
						if(fd->is_repeated())
						{
							reflection->AddInt32(&msg, fd, from_string<google::protobuf::int32>(child_value));
						}
						else
						{
							reflection->SetInt32(&msg, fd, from_string<google::protobuf::int32>(child_value));
						}

						break;
						
						// uint32, varint on the wire
					case FieldDescriptor::TYPE_UINT32:
						// uint32, exactly four bytes on the wire.
					case FieldDescriptor::TYPE_FIXED32:
						if(fd->is_repeated())
						{
							reflection->AddUInt32(&msg, fd, from_string<google::protobuf::uint32>(child_value));
						}
						else
						{
							reflection->SetUInt32(&msg, fd, from_string<google::protobuf::uint32>(child_value));
						}

						break;
					
						// int64, varint on the wire.  Negative numbers
						// take 10 bytes.  Use TYPE_SINT64 if negative
						// values are likely.
					case FieldDescriptor::TYPE_INT64:
						// int64, exactly eight bytes on the wire
					case FieldDescriptor::TYPE_SFIXED64:
						// int64, ZigZag-encoded varint on the wire
					case FieldDescriptor::TYPE_SINT64:
						if(fd->is_repeated())
						{
							reflection->AddInt64(&msg, fd, from_string<google::protobuf::int64>(child_value));
						}
						else
						{
							reflection->SetInt64(&msg, fd, from_string<google::protobuf::int64>(child_value));
						}
						break;

						// uint64, varint on the wire.
					case FieldDescriptor::TYPE_UINT64:
						// uint64, exactly eight bytes on the wire.
					case FieldDescriptor::TYPE_FIXED64:
						if(fd->is_repeated())
						{
							reflection->AddUInt64(&msg, fd, from_string<google::protobuf::uint64>(child_value));
						}
						else
						{
							reflection->SetUInt64(&msg, fd, from_string<google::protobuf::uint64>(child_value));
						}

						break;

						// bool, varint on the wire.
					case FieldDescriptor::TYPE_BOOL:
						if(fd->is_repeated())
						{
							reflection->AddBool(&msg, fd, from_string<bool>(child_value));
						}
						else
						{
							reflection->SetBool(&msg, fd, from_string<bool>(child_value));
						}

						break;

						// UTF-8 text.
					case FieldDescriptor::TYPE_STRING:
						// Arbitrary byte array.
					case FieldDescriptor::TYPE_BYTES:
						if(fd->is_repeated())
						{
							reflection->AddString(&msg, fd, child_value);
						}
						else
						{
							reflection->SetString(&msg, fd, child_value);
						}

						break;

						// Tag-delimited message.  Deprecated.
					case FieldDescriptor::TYPE_GROUP:
						// Length-delimited message.
					case FieldDescriptor::TYPE_MESSAGE:
						assert(0);
						return false;
						break;
						
						// Enum, varint on the wire
					case FieldDescriptor::TYPE_ENUM:
						{
							const google::protobuf::EnumValueDescriptor* evd = fd->enum_type()->FindValueByNumber(from_string<int>(child_value));
							if(!evd)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddEnum(&msg, fd, evd);
							}
							else
							{
								reflection->SetEnum(&msg, fd, evd);
							}
						}
							
						break;
					default:
						assert(0);
						return false;
						break;
					}
				}
			}
			
			break;
		case TiXmlNode::TINYXML_DECLARATION:
		case TiXmlNode::TINYXML_COMMENT:
			//ignore
			break;
		case TiXmlNode::TINYXML_UNKNOWN:
		case TiXmlNode::TINYXML_DOCUMENT:
		case TiXmlNode::TINYXML_TYPECOUNT:
		default:
			assert(0);
			return false;
			break;
		}
	}
	
	//解析XML属性
	if(!parse_xmlattr2proto(node->ToElement(), msg))
	{
		return false;
	}

	return true;
}

bool tinyxml2proto(const std::string& xml, google::protobuf::Message& msg)
{
	TiXmlDocument doc;
	doc.Parse(xml.c_str());
	TiXmlElement* root_ele = doc.RootElement();
	if(!root_ele)
	{
		return false;
	}

	const google::protobuf::Reflection* reflection = msg.GetReflection();
	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(INTER_PROTO_TINYXML_NAME);
	if(fd && !fd->is_repeated() && (fd->type() == FieldDescriptor::TYPE_STRING || fd->type() == FieldDescriptor::TYPE_BYTES))
	{
		reflection->SetString(&msg, fd, root_ele->ValueStr());
	}

	if(!parse_xml2proto_msg(root_ele, msg))
	{
		return false;
	}

	return true;
} 

//---------------------------------------------------------------------------------------------------------
static inline bool is_attribute(const std::string& str)
{
	if(str.size() > INTER_PROTO_TINYXML_ATTR_SIZE && str.substr(0, INTER_PROTO_TINYXML_ATTR_SIZE) == INTER_PROTO_TINYXML_ATTR)
	{
		return true;
	}

	return false;
}

static inline std::string get_attribute_name(const std::string& str)
{
	assert(is_attribute(str));
	return str.substr(INTER_PROTO_TINYXML_ATTR_SIZE);
}

static inline bool is_text(const std::string& str)
{
	return str == INTER_PROTO_TINYXML_VALUE;
}

static bool proto_fd2xml_attr(const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, TiXmlElement* element, const std::string& name)
{
	const google::protobuf::Reflection* reflection = msg.GetReflection();
	switch(fd->type())
	{
		// double, exactly eight bytes on the wire.
	case FieldDescriptor::TYPE_DOUBLE:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				element->SetAttribute(name, to_string(reflection->GetRepeatedDouble(msg, fd, 0)));
			}
		}
		else
		{
			element->SetAttribute(name, to_string(reflection->GetDouble(msg, fd)));
		}

		break;

		// float, exactly four bytes on the wire.
	case FieldDescriptor::TYPE_FLOAT:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				element->SetAttribute(name, to_string(reflection->GetRepeatedFloat(msg, fd, 0)));
			}
		}
		else
		{
			element->SetAttribute(name, to_string(reflection->GetFloat(msg, fd)));
		}

		break;

		// int32, varint on the wire.  Negative numbers
		// take 10 bytes.  Use TYPE_SINT32 if negative
		// values are likely.
	case FieldDescriptor::TYPE_INT32:
		// int32, exactly four bytes on the wire
	case FieldDescriptor::TYPE_SFIXED32:
		// int32, ZigZag-encoded varint on the wire
	case FieldDescriptor::TYPE_SINT32:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				element->SetAttribute(name, to_string(reflection->GetRepeatedInt32(msg, fd, 0)));
			}
		}
		else
		{
			element->SetAttribute(name, to_string(reflection->GetInt32(msg, fd)));
		}

		break;

		// uint32, varint on the wire
	case FieldDescriptor::TYPE_UINT32:
		// uint32, exactly four bytes on the wire.
	case FieldDescriptor::TYPE_FIXED32:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				element->SetAttribute(name, to_string(reflection->GetRepeatedUInt32(msg, fd, 0)));
			}
		}
		else
		{
			element->SetAttribute(name, to_string(reflection->GetUInt32(msg, fd)));
		}

		break;

		// int64, varint on the wire.  Negative numbers
		// take 10 bytes.  Use TYPE_SINT64 if negative
		// values are likely.
	case FieldDescriptor::TYPE_INT64:
		// int64, exactly eight bytes on the wire
	case FieldDescriptor::TYPE_SFIXED64:
		// int64, ZigZag-encoded varint on the wire
	case FieldDescriptor::TYPE_SINT64:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				element->SetAttribute(name, to_string(reflection->GetRepeatedInt64(msg, fd, 0)));
			}
		}
		else
		{
			element->SetAttribute(name, to_string(reflection->GetInt64(msg, fd)));
		}

		break;

		// uint64, varint on the wire.
	case FieldDescriptor::TYPE_UINT64:
		// uint64, exactly eight bytes on the wire.
	case FieldDescriptor::TYPE_FIXED64:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				element->SetAttribute(name, to_string(reflection->GetRepeatedUInt64(msg, fd, 0)));
			}
		}
		else
		{
			element->SetAttribute(name, to_string(reflection->GetUInt64(msg, fd)));
		}

		break;

		// bool, varint on the wire.
	case FieldDescriptor::TYPE_BOOL:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				element->SetAttribute(name, to_string(reflection->GetRepeatedBool(msg, fd, 0)));
			}
		}
		else
		{
			element->SetAttribute(name, to_string(reflection->GetBool(msg, fd)));
		}

		break;

		// UTF-8 text.
	case FieldDescriptor::TYPE_STRING:
		// Arbitrary byte array.
	case FieldDescriptor::TYPE_BYTES:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				element->SetAttribute(name, reflection->GetRepeatedString(msg, fd, 0));
			}
		}
		else
		{
			element->SetAttribute(name, reflection->GetString(msg, fd));
		}

		break;

		// Tag-delimited message.  Deprecated.
	case FieldDescriptor::TYPE_GROUP:
		// Length-delimited message.
	case FieldDescriptor::TYPE_MESSAGE:
		assert(0);
		return false;
		break;

		// Enum, varint on the wire
	case FieldDescriptor::TYPE_ENUM:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				element->SetAttribute(name, to_string(reflection->GetRepeatedEnum(msg, fd, 0)->number()));
			}
		}
		else
		{
			element->SetAttribute(name, to_string(reflection->GetEnum(msg, fd)->number()));
		}

		break;
	default:
		assert(0);
		return false;
		break;
	}

	return true;
}

static bool proto_fd2xml_text(const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, TiXmlElement* element)
{
	const google::protobuf::Reflection* reflection = msg.GetReflection();
	switch(fd->type())
	{
		// double, exactly eight bytes on the wire.
	case FieldDescriptor::TYPE_DOUBLE:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedDouble(msg, fd, count)));
				element->LinkEndChild(temp_text);
			}
		}
		else
		{
			TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetDouble(msg, fd)));
			element->LinkEndChild(temp_text);
		}

		break;

		// float, exactly four bytes on the wire.
	case FieldDescriptor::TYPE_FLOAT:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedFloat(msg, fd, count)));
				element->LinkEndChild(temp_text);
			}
		}
		else
		{
			TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetFloat(msg, fd)));
			element->LinkEndChild(temp_text);
		}

		break;

		// int32, varint on the wire.  Negative numbers
		// take 10 bytes.  Use TYPE_SINT32 if negative
		// values are likely.
	case FieldDescriptor::TYPE_INT32:
		// int32, exactly four bytes on the wire
	case FieldDescriptor::TYPE_SFIXED32:
		// int32, ZigZag-encoded varint on the wire
	case FieldDescriptor::TYPE_SINT32:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedInt32(msg, fd, count)));
				element->LinkEndChild(temp_text);
			}
		}
		else
		{
			TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetInt32(msg, fd)));
			element->LinkEndChild(temp_text);
		}

		break;

		// uint32, varint on the wire
	case FieldDescriptor::TYPE_UINT32:
		// uint32, exactly four bytes on the wire.
	case FieldDescriptor::TYPE_FIXED32:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedUInt32(msg, fd, count)));
				element->LinkEndChild(temp_text);
			}
		}
		else
		{
			TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetUInt32(msg, fd)));
			element->LinkEndChild(temp_text);
		}

		break;

		// int64, varint on the wire.  Negative numbers
		// take 10 bytes.  Use TYPE_SINT64 if negative
		// values are likely.
	case FieldDescriptor::TYPE_INT64:
		// int64, exactly eight bytes on the wire
	case FieldDescriptor::TYPE_SFIXED64:
		// int64, ZigZag-encoded varint on the wire
	case FieldDescriptor::TYPE_SINT64:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedInt64(msg, fd, count)));
				element->LinkEndChild(temp_text);
			}
		}
		else
		{
			TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetInt64(msg, fd)));
			element->LinkEndChild(temp_text);
		}

		break;

		// uint64, varint on the wire.
	case FieldDescriptor::TYPE_UINT64:
		// uint64, exactly eight bytes on the wire.
	case FieldDescriptor::TYPE_FIXED64:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedUInt64(msg, fd, count)));
				element->LinkEndChild(temp_text);
			}
		}
		else
		{
			TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetUInt64(msg, fd)));
			element->LinkEndChild(temp_text);
		}

		break;

		// bool, varint on the wire.
	case FieldDescriptor::TYPE_BOOL:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedBool(msg, fd, count)));
				element->LinkEndChild(temp_text);
			}
		}
		else
		{
			TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetBool(msg, fd)));
			element->LinkEndChild(temp_text);
		}

		break;

		// UTF-8 text.
	case FieldDescriptor::TYPE_STRING:
		// Arbitrary byte array.
	case FieldDescriptor::TYPE_BYTES:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				TiXmlText* temp_text = new TiXmlText(reflection->GetRepeatedString(msg, fd, count));
				element->LinkEndChild(temp_text);
			}
		}
		else
		{
			TiXmlText* temp_text = new TiXmlText(reflection->GetString(msg, fd));
			element->LinkEndChild(temp_text);
		}

		break;

		// Tag-delimited message.  Deprecated.
	case FieldDescriptor::TYPE_GROUP:
		// Length-delimited message.
	case FieldDescriptor::TYPE_MESSAGE:
		assert(0);
		return false;
		break;

		// Enum, varint on the wire
	case FieldDescriptor::TYPE_ENUM:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedEnum(msg, fd, count)->number()));
				element->LinkEndChild(temp_text);
			}
		}
		else
		{
			TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetEnum(msg, fd)->number()));
			element->LinkEndChild(temp_text);
		}

		break;
	default:
		assert(0);
		return false;
		break;
	}

	return true;
}

static bool proto_msg2xml(const google::protobuf::Message& msg, TiXmlElement* element)
{
	assert(element);
	const google::protobuf::Reflection* reflection = msg.GetReflection();
	assert(reflection);
	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	assert(des);
	for(int count = 0; count < des->field_count(); ++count)
	{
		const google::protobuf::FieldDescriptor* fd = des->field(count);
		assert(fd);
		std::string key = fd->name();
		//没有设置的非repeated字段不组装进xml
		if(key == INTER_PROTO_TINYXML_NAME || (!fd->is_repeated() && !reflection->HasField(msg, fd)))
		{
			continue;
		}
		
		if(is_attribute(key))
		{
			if(!proto_fd2xml_attr(msg, fd, element, get_attribute_name(key)))
			{
				return false;
			}
		}
		else if(is_text(key))
		{
			if(!proto_fd2xml_text(msg, fd, element))
			{
				return false;
			}
		}
		else
		{
			switch(fd->type())
			{
				// double, exactly eight bytes on the wire.
			case FieldDescriptor::TYPE_DOUBLE:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedDouble(msg, fd, count)));
						temp_ele->LinkEndChild(temp_text);
						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
					TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetDouble(msg, fd)));
					temp_ele->LinkEndChild(temp_text);
					element->LinkEndChild(temp_ele);
				}

				break;

				// float, exactly four bytes on the wire.
			case FieldDescriptor::TYPE_FLOAT:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedFloat(msg, fd, count)));
						temp_ele->LinkEndChild(temp_text);
						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
					TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetFloat(msg, fd)));
					temp_ele->LinkEndChild(temp_text);
					element->LinkEndChild(temp_ele);
				}

				break;

				// int32, varint on the wire.  Negative numbers
				// take 10 bytes.  Use TYPE_SINT32 if negative
				// values are likely.
			case FieldDescriptor::TYPE_INT32:
				// int32, exactly four bytes on the wire
			case FieldDescriptor::TYPE_SFIXED32:
				// int32, ZigZag-encoded varint on the wire
			case FieldDescriptor::TYPE_SINT32:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedInt32(msg, fd, count)));
						temp_ele->LinkEndChild(temp_text);
						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
					TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetInt32(msg, fd)));
					temp_ele->LinkEndChild(temp_text);
					element->LinkEndChild(temp_ele);
				}

				break;

				// uint32, varint on the wire
			case FieldDescriptor::TYPE_UINT32:
				// uint32, exactly four bytes on the wire.
			case FieldDescriptor::TYPE_FIXED32:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedUInt32(msg, fd, count)));
						temp_ele->LinkEndChild(temp_text);
						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
					TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetUInt32(msg, fd)));
					temp_ele->LinkEndChild(temp_text);
					element->LinkEndChild(temp_ele);
				}

				break;

				// int64, varint on the wire.  Negative numbers
				// take 10 bytes.  Use TYPE_SINT64 if negative
				// values are likely.
			case FieldDescriptor::TYPE_INT64:
				// int64, exactly eight bytes on the wire
			case FieldDescriptor::TYPE_SFIXED64:
				// int64, ZigZag-encoded varint on the wire
			case FieldDescriptor::TYPE_SINT64:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedInt64(msg, fd, count)));
						temp_ele->LinkEndChild(temp_text);
						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
					TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetInt64(msg, fd)));
					temp_ele->LinkEndChild(temp_text);
					element->LinkEndChild(temp_ele);
				}

				break;

				// uint64, varint on the wire.
			case FieldDescriptor::TYPE_UINT64:
				// uint64, exactly eight bytes on the wire.
			case FieldDescriptor::TYPE_FIXED64:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedUInt64(msg, fd, count)));
						temp_ele->LinkEndChild(temp_text);
						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
					TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetUInt64(msg, fd)));
					temp_ele->LinkEndChild(temp_text);
					element->LinkEndChild(temp_ele);
				}

				break;

				// bool, varint on the wire.
			case FieldDescriptor::TYPE_BOOL:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedBool(msg, fd, count)));
						temp_ele->LinkEndChild(temp_text);
						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
					TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetBool(msg, fd)));
					temp_ele->LinkEndChild(temp_text);
					element->LinkEndChild(temp_ele);
				}

				break;

				// UTF-8 text.
			case FieldDescriptor::TYPE_STRING:
				// Arbitrary byte array.
			case FieldDescriptor::TYPE_BYTES:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						TiXmlText* temp_text = new TiXmlText(reflection->GetRepeatedString(msg, fd, count));
						temp_ele->LinkEndChild(temp_text);
						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
					TiXmlText* temp_text = new TiXmlText(reflection->GetString(msg, fd));
					temp_ele->LinkEndChild(temp_text);
					element->LinkEndChild(temp_ele);
				}

				break;

				// Tag-delimited message.  Deprecated.
			case FieldDescriptor::TYPE_GROUP:
				// Length-delimited message.
			case FieldDescriptor::TYPE_MESSAGE:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						if(!proto_msg2xml(reflection->GetRepeatedMessage(msg, fd, count), temp_ele))
						{
							delete temp_ele;
							return false;
						}

						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
				//宏用于解决宏定义与函数名冲突
				#pragma push_macro("GetMessage")
				#undef GetMessage
					if(!proto_msg2xml(reflection->GetMessage(msg, fd), temp_ele))
					{
						delete temp_ele;
						return false;
					}

				#pragma pop_macro("GetMessage")
					element->LinkEndChild(temp_ele);
				}

				break;

				// Enum, varint on the wire
			case FieldDescriptor::TYPE_ENUM:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						TiXmlElement* temp_ele = new TiXmlElement(key);
						TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetRepeatedEnum(msg, fd, count)->number()));
						temp_ele->LinkEndChild(temp_text);
						element->LinkEndChild(temp_ele);
					}
				}
				else
				{
					TiXmlElement* temp_ele = new TiXmlElement(key);
					TiXmlText* temp_text = new TiXmlText(to_string(reflection->GetEnum(msg, fd)->number()));
					temp_ele->LinkEndChild(temp_text);
					element->LinkEndChild(temp_ele);
				}

				break;
			default:
				assert(0);
				return false;
				break;
			}
		}
	}

	return true;
}

bool proto2tinyxml(const google::protobuf::Message& msg, std::string& xml, tinyxml_type type/* = TINYXML_UTF8*/)
{
	TiXmlDocument doc;
	TiXmlDeclaration *declaration = NULL;
	if(type == TINYXML_GB2312)
	{
		declaration = new TiXmlDeclaration("1.0", "gb2312", "yes");
	}
	else if(type == TINYXML_UTF8)
	{
		declaration = new TiXmlDeclaration("1.0", "utf-8", "yes");
	}

	if(declaration)
	{
		doc.LinkEndChild(declaration);
	}
	
	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(INTER_PROTO_TINYXML_NAME);
	if(!fd || fd->is_repeated() || (fd->type() != FieldDescriptor::TYPE_STRING && fd->type() != FieldDescriptor::TYPE_BYTES))
	{
		assert(0);
		return false;
	}
	
	const google::protobuf::Reflection* reflection = msg.GetReflection();
	TiXmlElement* root_ele = new TiXmlElement(reflection->GetString(msg, fd));
	doc.LinkEndChild(root_ele);
	if(!proto_msg2xml(msg, root_ele))
	{
		return false;
	}

	// Declare a printer    
	TiXmlPrinter printer;
	// attach it to the document you want to convert in to a std::string 
	doc.Accept(&printer);
	// Create a std::string and copy your document data in to the string    
	xml = printer.Str();
	return true;
} 
#ifndef _INTER_PROTO_CMARKUP_H_
#define _INTER_PROTO_CMARKUP_H_

#include <string>
#include "google/protobuf/message.h"

bool cmarkup2proto(const std::string& xml, google::protobuf::Message& msg);

enum cmarkup_type
{
	CMARKUP_GB2312,
	CMARKUP_UTF8,
};

bool proto2cmarkup(const google::protobuf::Message& msg, std::string& xml, cmarkup_type type = CMARKUP_GB2312);

#endif //_INTER_PROTO_CMARKUP_H_

#include "InterProtoCmarkup.h"
#include "Markup.h"
#include "google/protobuf/descriptor.h"
#include "utils/utils.h"

#define INTER_PROTO_CMARKUP_NAME		"_name"
#define INTER_PROTO_CMARKUP_VALUE		"_value"
#define INTER_PROTO_CMARKUP_ATTR		"_attr_"
#define INTER_PROTO_CMARKUP_ATTR_SIZE	6

using namespace google::protobuf;

template<class T>
static T get_xml_field(CMarkup& doc, bool& get_ok)
{
	if(!doc.IntoElem())
	{
		get_ok = false;
		return T();
	}

	while(doc.FindNode())
	{
		if(doc.GetNodeType() == CMarkup::MNT_TEXT)
		{
			get_ok = true;
			T ret = from_string<T>(string_trim(doc.GetData(), " \r\n\t\""));
			doc.OutOfElem();
			return ret;
		}
	}

	doc.OutOfElem();
	get_ok = false;
	return T();
}

template<>
static std::string get_xml_field<std::string>(CMarkup& doc, bool& get_ok)
{
	if(!doc.IntoElem())
	{
		get_ok = false;
		return "";
	}

	while(doc.FindNode())
	{
		if(doc.GetNodeType() == CMarkup::MNT_TEXT)
		{
			get_ok = true;
			std::string ret = string_trim(doc.GetData(), " \r\n\t\"");
			doc.OutOfElem();
			return ret;
		}
	}

	doc.OutOfElem();
	get_ok = false;
	return "";
}

template<>
static bool get_xml_field<bool>(CMarkup& doc, bool& get_ok)
{
	if(!doc.IntoElem())
	{
		get_ok = false;
		return false;
	}

	while(doc.FindNode())
	{
		if(doc.GetNodeType() == CMarkup::MNT_TEXT)
		{
			get_ok = true;
			bool ret = (bool)from_string<int>(string_trim(doc.GetData(), " \r\n\t\""));
			doc.OutOfElem();
			return ret;
		}
	}

	doc.OutOfElem();
	get_ok = false;
	return false;
}

static bool parse_xmlattr2proto(CMarkup& doc, google::protobuf::Message& msg)
{
	//解析XML文件
	const google::protobuf::Reflection* reflection = msg.GetReflection();
	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	int attr_count = 0;
#pragma warning(push)
#pragma warning(disable:4127)
	while(true)
	{
#pragma warning(pop)
		std::string name = doc.GetAttribName(attr_count);
		if(name.empty())
		{
			break;
		}
		std::string value = doc.GetAttrib(name);
		const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(INTER_PROTO_CMARKUP_ATTR + name);
		if(fd)
		{
			switch(fd->type())
			{
				// double, exactly eight bytes on the wire.
			case FieldDescriptor::TYPE_DOUBLE:
				if(fd->is_repeated())
				{
					reflection->AddDouble(&msg, fd, from_string<double>(value));
				}
				else
				{
					reflection->SetDouble(&msg, fd, from_string<double>(value));
				}

				break;

				// float, exactly four bytes on the wire.
			case FieldDescriptor::TYPE_FLOAT:
				if(fd->is_repeated())
				{
					reflection->AddFloat(&msg, fd, from_string<float>(value));
				}
				else
				{
					reflection->SetFloat(&msg, fd, from_string<float>(value));
				}

				break;

				// int32, varint on the wire.  Negative numbers
				// take 10 bytes.  Use TYPE_SINT32 if negative
				// values are likely.
			case FieldDescriptor::TYPE_INT32:
				// int32, exactly four bytes on the wire
			case FieldDescriptor::TYPE_SFIXED32:
				// int32, ZigZag-encoded varint on the wire
			case FieldDescriptor::TYPE_SINT32:
				if(fd->is_repeated())
				{
					reflection->AddInt32(&msg, fd, from_string<google::protobuf::int32>(value));
				}
				else
				{
					reflection->SetInt32(&msg, fd, from_string<google::protobuf::int32>(value));
				}

				break;

				// uint32, varint on the wire
			case FieldDescriptor::TYPE_UINT32:
				// uint32, exactly four bytes on the wire.
			case FieldDescriptor::TYPE_FIXED32:
				if(fd->is_repeated())
				{
					reflection->AddUInt32(&msg, fd, from_string<google::protobuf::uint32>(value));
				}
				else
				{
					reflection->SetUInt32(&msg, fd, from_string<google::protobuf::uint32>(value));
				}

				break;

				// int64, varint on the wire.  Negative numbers
				// take 10 bytes.  Use TYPE_SINT64 if negative
				// values are likely.
			case FieldDescriptor::TYPE_INT64:
				// int64, exactly eight bytes on the wire
			case FieldDescriptor::TYPE_SFIXED64:
				// int64, ZigZag-encoded varint on the wire
			case FieldDescriptor::TYPE_SINT64:
				if(fd->is_repeated())
				{
					reflection->AddInt64(&msg, fd, from_string<google::protobuf::int64>(value));
				}
				else
				{
					reflection->SetInt64(&msg, fd, from_string<google::protobuf::int64>(value));
				}
				break;

				// uint64, varint on the wire.
			case FieldDescriptor::TYPE_UINT64:
				// uint64, exactly eight bytes on the wire.
			case FieldDescriptor::TYPE_FIXED64:
				if(fd->is_repeated())
				{
					reflection->AddUInt64(&msg, fd, from_string<google::protobuf::uint64>(value));
				}
				else
				{
					reflection->SetUInt64(&msg, fd, from_string<google::protobuf::uint64>(value));
				}

				break;

				// bool, varint on the wire.
			case FieldDescriptor::TYPE_BOOL:
				if(fd->is_repeated())
				{
					reflection->AddBool(&msg, fd, from_string<bool>(value));
				}
				else
				{
					reflection->SetBool(&msg, fd, from_string<bool>(value));
				}

				break;

				// UTF-8 text.
			case FieldDescriptor::TYPE_STRING:
				// Arbitrary byte array.
			case FieldDescriptor::TYPE_BYTES:
				if(fd->is_repeated())
				{
					reflection->AddString(&msg, fd, value);
				}
				else
				{
					reflection->SetString(&msg, fd, value);
				}

				break;

				// Tag-delimited message.  Deprecated.
			case FieldDescriptor::TYPE_GROUP:
				// Length-delimited message.
			case FieldDescriptor::TYPE_MESSAGE:
				assert(0);
				return false;
				break;

				// Enum, varint on the wire
			case FieldDescriptor::TYPE_ENUM:
				{
					const google::protobuf::EnumValueDescriptor* evd = fd->enum_type()->FindValueByNumber(from_string<int>(value));
					if(!evd)
					{
						return false;
					}

					if(fd->is_repeated())
					{
						reflection->AddEnum(&msg, fd, evd);
					}
					else
					{
						reflection->SetEnum(&msg, fd, evd);
					}
				}

				break;
			default:
				assert(0);
				return false;
				break;
			}
		}

		++attr_count;
	}

	return true;
}

static bool parse_xml2proto_msg(CMarkup& doc, google::protobuf::Message& msg)
{
	assert(doc.GetNodeType() == CMarkup::MNT_ELEMENT);
	if(!doc.IntoElem())
	{
		assert(0);
		return false;
	}

	//解析XML文件
	const google::protobuf::Reflection* reflection = msg.GetReflection();
	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	while(doc.FindNode())
	{
		switch(doc.GetNodeType())
		{
		case CMarkup::MNT_ELEMENT:
			{
				std::string tag_name = doc.GetTagName();
				const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(tag_name);
				if(fd)
				{
					switch(fd->type())
					{
						// double, exactly eight bytes on the wire.
					case FieldDescriptor::TYPE_DOUBLE:
						{
							bool get_ok = false;
							double temp_value = get_xml_field<double>(doc, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddDouble(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetDouble(&msg, fd, temp_value);
							}
						}

						break;

						// float, exactly four bytes on the wire.
					case FieldDescriptor::TYPE_FLOAT:
						{
							bool get_ok = false;
							float temp_value = get_xml_field<float>(doc, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddFloat(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetFloat(&msg, fd, temp_value);
							}
						}
						break;

						// int32, varint on the wire.  Negative numbers
						// take 10 bytes.  Use TYPE_SINT32 if negative
						// values are likely.
					case FieldDescriptor::TYPE_INT32:
						// int32, exactly four bytes on the wire
					case FieldDescriptor::TYPE_SFIXED32:
						// int32, ZigZag-encoded varint on the wire
					case FieldDescriptor::TYPE_SINT32:
						{
							bool get_ok = false;
							google::protobuf::int32 temp_value = get_xml_field<google::protobuf::int32>(doc, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddInt32(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetInt32(&msg, fd, temp_value);
							}
						}

						break;

						// uint32, varint on the wire
					case FieldDescriptor::TYPE_UINT32:
						// uint32, exactly four bytes on the wire.
					case FieldDescriptor::TYPE_FIXED32:
						{
							bool get_ok = false;
							google::protobuf::uint32 temp_value = get_xml_field<google::protobuf::uint32>(doc, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddUInt32(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetUInt32(&msg, fd, temp_value);
							}
						}

						break;

						// int64, varint on the wire.  Negative numbers
						// take 10 bytes.  Use TYPE_SINT64 if negative
						// values are likely.
					case FieldDescriptor::TYPE_INT64:
						// int64, exactly eight bytes on the wire
					case FieldDescriptor::TYPE_SFIXED64:
						// int64, ZigZag-encoded varint on the wire
					case FieldDescriptor::TYPE_SINT64:
						{
							bool get_ok = false;
							google::protobuf::int64 temp_value = get_xml_field<google::protobuf::int64>(doc, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddInt64(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetInt64(&msg, fd, temp_value);
							}
						}

						break;

						// uint64, varint on the wire.
					case FieldDescriptor::TYPE_UINT64:
						// uint64, exactly eight bytes on the wire.
					case FieldDescriptor::TYPE_FIXED64:
						{
							bool get_ok = false;
							google::protobuf::uint64 temp_value = get_xml_field<google::protobuf::uint64>(doc, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddUInt64(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetUInt64(&msg, fd, temp_value);
							}
						}

						break;

						// bool, varint on the wire.
					case FieldDescriptor::TYPE_BOOL:
						{
							bool get_ok = false;
							bool temp_value = get_xml_field<bool>(doc, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddBool(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetBool(&msg, fd, temp_value);
							}
						}

						break;

						// UTF-8 text.
					case FieldDescriptor::TYPE_STRING:
						// Arbitrary byte array.
					case FieldDescriptor::TYPE_BYTES:
						{
							bool get_ok = false;
							std::string temp_value = get_xml_field<std::string>(doc, get_ok);
							if(!get_ok)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddString(&msg, fd, temp_value);
							}
							else
							{
								reflection->SetString(&msg, fd, temp_value);
							}
						}

						break;

						// Tag-delimited message.  Deprecated.
					case FieldDescriptor::TYPE_GROUP:
						// Length-delimited message.
					case FieldDescriptor::TYPE_MESSAGE:
						if(fd->is_repeated())
						{
							if(!parse_xml2proto_msg(doc, *reflection->AddMessage(&msg, fd)))
							{
								return false;
							}
						}
						else
						{
							if(!parse_xml2proto_msg(doc, *reflection->MutableMessage(&msg, fd)))
							{
								return false;
							}
						}
						
						break;

						// Enum, varint on the wire
					case FieldDescriptor::TYPE_ENUM:
						{
							bool get_ok = false;
							int temp_value = get_xml_field<int>(doc, get_ok);
							if(!get_ok)
							{
								return false;
							}

							const google::protobuf::EnumValueDescriptor* evd = fd->enum_type()->FindValueByNumber(temp_value);
							if(!evd)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddEnum(&msg, fd, evd);
							}
							else
							{
								reflection->SetEnum(&msg, fd, evd);
							}
						}

						break;
					default:
						assert(0);
						return false;
						break;
					}
				}
			}

			break;
		case CMarkup::MNT_TEXT:
			{
				const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(INTER_PROTO_CMARKUP_VALUE);
				if(fd)
				{
					std::string child_value = string_trim(doc.GetData(), " \r\n\t\"");
					switch(fd->type())
					{
						// double, exactly eight bytes on the wire.
					case FieldDescriptor::TYPE_DOUBLE:
						if(fd->is_repeated())
						{
							reflection->AddDouble(&msg, fd, from_string<double>(child_value));
						}
						else
						{
							reflection->SetDouble(&msg, fd, from_string<double>(child_value));
						}

						break;

						// float, exactly four bytes on the wire.
					case FieldDescriptor::TYPE_FLOAT:
						if(fd->is_repeated())
						{
							reflection->AddFloat(&msg, fd, from_string<float>(child_value));
						}
						else
						{
							reflection->SetFloat(&msg, fd, from_string<float>(child_value));
						}

						break;

						// int32, varint on the wire.  Negative numbers
						// take 10 bytes.  Use TYPE_SINT32 if negative
						// values are likely.
					case FieldDescriptor::TYPE_INT32:
						// int32, exactly four bytes on the wire
					case FieldDescriptor::TYPE_SFIXED32:
						// int32, ZigZag-encoded varint on the wire
					case FieldDescriptor::TYPE_SINT32:
						if(fd->is_repeated())
						{
							reflection->AddInt32(&msg, fd, from_string<google::protobuf::int32>(child_value));
						}
						else
						{
							reflection->SetInt32(&msg, fd, from_string<google::protobuf::int32>(child_value));
						}

						break;

						// uint32, varint on the wire
					case FieldDescriptor::TYPE_UINT32:
						// uint32, exactly four bytes on the wire.
					case FieldDescriptor::TYPE_FIXED32:
						if(fd->is_repeated())
						{
							reflection->AddUInt32(&msg, fd, from_string<google::protobuf::uint32>(child_value));
						}
						else
						{
							reflection->SetUInt32(&msg, fd, from_string<google::protobuf::uint32>(child_value));
						}

						break;

						// int64, varint on the wire.  Negative numbers
						// take 10 bytes.  Use TYPE_SINT64 if negative
						// values are likely.
					case FieldDescriptor::TYPE_INT64:
						// int64, exactly eight bytes on the wire
					case FieldDescriptor::TYPE_SFIXED64:
						// int64, ZigZag-encoded varint on the wire
					case FieldDescriptor::TYPE_SINT64:
						if(fd->is_repeated())
						{
							reflection->AddInt64(&msg, fd, from_string<google::protobuf::int64>(child_value));
						}
						else
						{
							reflection->SetInt64(&msg, fd, from_string<google::protobuf::int64>(child_value));
						}
						break;

						// uint64, varint on the wire.
					case FieldDescriptor::TYPE_UINT64:
						// uint64, exactly eight bytes on the wire.
					case FieldDescriptor::TYPE_FIXED64:
						if(fd->is_repeated())
						{
							reflection->AddUInt64(&msg, fd, from_string<google::protobuf::uint64>(child_value));
						}
						else
						{
							reflection->SetUInt64(&msg, fd, from_string<google::protobuf::uint64>(child_value));
						}

						break;

						// bool, varint on the wire.
					case FieldDescriptor::TYPE_BOOL:
						if(fd->is_repeated())
						{
							reflection->AddBool(&msg, fd, from_string<bool>(child_value));
						}
						else
						{
							reflection->SetBool(&msg, fd, from_string<bool>(child_value));
						}

						break;

						// UTF-8 text.
					case FieldDescriptor::TYPE_STRING:
						// Arbitrary byte array.
					case FieldDescriptor::TYPE_BYTES:
						if(fd->is_repeated())
						{
							reflection->AddString(&msg, fd, child_value);
						}
						else
						{
							reflection->SetString(&msg, fd, child_value);
						}

						break;

						// Tag-delimited message.  Deprecated.
					case FieldDescriptor::TYPE_GROUP:
						// Length-delimited message.
					case FieldDescriptor::TYPE_MESSAGE:
						assert(0);
						return false;
						break;

						// Enum, varint on the wire
					case FieldDescriptor::TYPE_ENUM:
						{
							const google::protobuf::EnumValueDescriptor* evd = fd->enum_type()->FindValueByNumber(from_string<int>(child_value));
							if(!evd)
							{
								return false;
							}

							if(fd->is_repeated())
							{
								reflection->AddEnum(&msg, fd, evd);
							}
							else
							{
								reflection->SetEnum(&msg, fd, evd);
							}
						}

						break;
					default:
						assert(0);
						return false;
						break;
					}
				}
			}

			break;
		case CMarkup::MNT_TEXT_AND_WHITESPACE:
		case CMarkup::MNT_CDATA_SECTION:
		case CMarkup::MNT_PROCESSING_INSTRUCTION:
			assert(0);
			return false;
			break;
		case CMarkup::MNT_WHITESPACE:
		case CMarkup::MNT_COMMENT:
			//ignore
			break;
		case CMarkup::MNT_DOCUMENT_TYPE:
		case CMarkup::MNT_EXCLUDE_WHITESPACE:
		case CMarkup::MNT_LONE_END_TAG:
		case CMarkup::MNT_NODE_ERROR:
		default:
			assert(0);
			return false;
			break;
		}
	}

	doc.OutOfElem();
	//解析XML属性
	if(!parse_xmlattr2proto(doc, msg))
	{
		return false;
	}

	return true;
}

bool cmarkup2proto(const std::string& xml, google::protobuf::Message& msg)
{
	CMarkup doc(xml);
	bool find_ok = doc.FindElem();
	if(!find_ok)
	{
		return false;
	}
	
	const google::protobuf::Reflection* reflection = msg.GetReflection();
	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(INTER_PROTO_CMARKUP_NAME);
	if(fd && !fd->is_repeated() && (fd->type() == FieldDescriptor::TYPE_STRING || fd->type() == FieldDescriptor::TYPE_BYTES))
	{
		reflection->SetString(&msg, fd, doc.GetTagName());
	}

	if(!parse_xml2proto_msg(doc, msg))
	{
		return false;
	}

	return true;
} 

//---------------------------------------------------------------------------------------------------------
static inline bool is_attribute(const std::string& str)
{
	if(str.size() > INTER_PROTO_CMARKUP_ATTR_SIZE && str.substr(0, INTER_PROTO_CMARKUP_ATTR_SIZE) == INTER_PROTO_CMARKUP_ATTR)
	{
		return true;
	}

	return false;
}

static inline std::string get_attribute_name(const std::string& str)
{
	assert(is_attribute(str));
	return str.substr(INTER_PROTO_CMARKUP_ATTR_SIZE);
}

static inline bool is_text(const std::string& str)
{
	return str == INTER_PROTO_CMARKUP_VALUE;
}

static bool proto_fd2xml_attr(const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, CMarkup& doc, const std::string& name)
{
	//先定位主元素才可以进行属性操作
	if(!doc.OutOfElem())
	{
		return false;
	}

	const google::protobuf::Reflection* reflection = msg.GetReflection();
	switch(fd->type())
	{
		// double, exactly eight bytes on the wire.
	case FieldDescriptor::TYPE_DOUBLE:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				doc.AddAttrib(name, to_string(reflection->GetRepeatedDouble(msg, fd, 0)));
			}
		}
		else
		{
			doc.AddAttrib(name, to_string(reflection->GetDouble(msg, fd)));
		}

		break;

		// float, exactly four bytes on the wire.
	case FieldDescriptor::TYPE_FLOAT:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				doc.AddAttrib(name, to_string(reflection->GetRepeatedFloat(msg, fd, 0)));
			}
		}
		else
		{
			doc.AddAttrib(name, to_string(reflection->GetFloat(msg, fd)));
		}

		break;

		// int32, varint on the wire.  Negative numbers
		// take 10 bytes.  Use TYPE_SINT32 if negative
		// values are likely.
	case FieldDescriptor::TYPE_INT32:
		// int32, exactly four bytes on the wire
	case FieldDescriptor::TYPE_SFIXED32:
		// int32, ZigZag-encoded varint on the wire
	case FieldDescriptor::TYPE_SINT32:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				doc.AddAttrib(name, to_string(reflection->GetRepeatedInt32(msg, fd, 0)));
			}
		}
		else
		{
			doc.AddAttrib(name, to_string(reflection->GetInt32(msg, fd)));
		}

		break;

		// uint32, varint on the wire
	case FieldDescriptor::TYPE_UINT32:
		// uint32, exactly four bytes on the wire.
	case FieldDescriptor::TYPE_FIXED32:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				doc.AddAttrib(name, to_string(reflection->GetRepeatedUInt32(msg, fd, 0)));
			}
		}
		else
		{
			doc.AddAttrib(name, to_string(reflection->GetUInt32(msg, fd)));
		}

		break;

		// int64, varint on the wire.  Negative numbers
		// take 10 bytes.  Use TYPE_SINT64 if negative
		// values are likely.
	case FieldDescriptor::TYPE_INT64:
		// int64, exactly eight bytes on the wire
	case FieldDescriptor::TYPE_SFIXED64:
		// int64, ZigZag-encoded varint on the wire
	case FieldDescriptor::TYPE_SINT64:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				doc.AddAttrib(name, to_string(reflection->GetRepeatedInt64(msg, fd, 0)));
			}
		}
		else
		{
			doc.AddAttrib(name, to_string(reflection->GetInt64(msg, fd)));
		}

		break;

		// uint64, varint on the wire.
	case FieldDescriptor::TYPE_UINT64:
		// uint64, exactly eight bytes on the wire.
	case FieldDescriptor::TYPE_FIXED64:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				doc.AddAttrib(name, to_string(reflection->GetRepeatedUInt64(msg, fd, 0)));
			}
		}
		else
		{
			doc.AddAttrib(name, to_string(reflection->GetUInt64(msg, fd)));
		}

		break;

		// bool, varint on the wire.
	case FieldDescriptor::TYPE_BOOL:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				doc.AddAttrib(name, to_string(reflection->GetRepeatedBool(msg, fd, 0)));
			}
		}
		else
		{
			doc.AddAttrib(name, to_string(reflection->GetBool(msg, fd)));
		}

		break;

		// UTF-8 text.
	case FieldDescriptor::TYPE_STRING:
		// Arbitrary byte array.
	case FieldDescriptor::TYPE_BYTES:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				doc.AddAttrib(name, reflection->GetRepeatedString(msg, fd, 0));
			}
		}
		else
		{
			doc.AddAttrib(name, reflection->GetString(msg, fd));
		}

		break;

		// Tag-delimited message.  Deprecated.
	case FieldDescriptor::TYPE_GROUP:
		// Length-delimited message.
	case FieldDescriptor::TYPE_MESSAGE:
		assert(0);
		return false;
		break;

		// Enum, varint on the wire
	case FieldDescriptor::TYPE_ENUM:
		if(fd->is_repeated())
		{
			if(reflection->FieldSize(msg, fd) > 0)
			{
				doc.AddAttrib(name, reflection->GetRepeatedEnum(msg, fd, 0)->number());
			}
		}
		else
		{
			doc.AddAttrib(name, reflection->GetEnum(msg, fd)->number());
		}

		break;
	default:
		assert(0);
		return false;
		break;
	}

	//重新进入tag
	doc.IntoElem();
	return true;
}

static bool proto_fd2xml_text(const google::protobuf::Message& msg, const google::protobuf::FieldDescriptor* fd, CMarkup& doc)
{
	//先定位主元素才可以进行数据操作
	if(!doc.OutOfElem())
	{
		return false;
	}

	const google::protobuf::Reflection* reflection = msg.GetReflection();
	switch(fd->type())
	{
		// double, exactly eight bytes on the wire.
	case FieldDescriptor::TYPE_DOUBLE:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				doc.SetData(to_string(reflection->GetRepeatedDouble(msg, fd, count)));
			}
		}
		else
		{
			doc.SetData(to_string(reflection->GetDouble(msg, fd)));
		}

		break;

		// float, exactly four bytes on the wire.
	case FieldDescriptor::TYPE_FLOAT:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				doc.SetData(to_string(reflection->GetRepeatedFloat(msg, fd, count)));
			}
		}
		else
		{
			doc.SetData(to_string(reflection->GetFloat(msg, fd)));
		}

		break;

		// int32, varint on the wire.  Negative numbers
		// take 10 bytes.  Use TYPE_SINT32 if negative
		// values are likely.
	case FieldDescriptor::TYPE_INT32:
		// int32, exactly four bytes on the wire
	case FieldDescriptor::TYPE_SFIXED32:
		// int32, ZigZag-encoded varint on the wire
	case FieldDescriptor::TYPE_SINT32:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				doc.SetData(to_string(reflection->GetRepeatedInt32(msg, fd, count)));
			}
		}
		else
		{
			doc.SetData(to_string(reflection->GetInt32(msg, fd)));
		}

		break;

		// uint32, varint on the wire
	case FieldDescriptor::TYPE_UINT32:
		// uint32, exactly four bytes on the wire.
	case FieldDescriptor::TYPE_FIXED32:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				doc.SetData(to_string(reflection->GetRepeatedUInt32(msg, fd, count)));
			}
		}
		else
		{
			doc.SetData(to_string(reflection->GetUInt32(msg, fd)));
		}

		break;

		// int64, varint on the wire.  Negative numbers
		// take 10 bytes.  Use TYPE_SINT64 if negative
		// values are likely.
	case FieldDescriptor::TYPE_INT64:
		// int64, exactly eight bytes on the wire
	case FieldDescriptor::TYPE_SFIXED64:
		// int64, ZigZag-encoded varint on the wire
	case FieldDescriptor::TYPE_SINT64:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				doc.SetData(to_string(reflection->GetRepeatedInt64(msg, fd, count)));
			}
		}
		else
		{
			doc.SetData(to_string(reflection->GetInt64(msg, fd)));
		}

		break;

		// uint64, varint on the wire.
	case FieldDescriptor::TYPE_UINT64:
		// uint64, exactly eight bytes on the wire.
	case FieldDescriptor::TYPE_FIXED64:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				doc.SetData(to_string(reflection->GetRepeatedUInt64(msg, fd, count)));
			}
		}
		else
		{
			doc.SetData(to_string(reflection->GetUInt64(msg, fd)));
		}

		break;

		// bool, varint on the wire.
	case FieldDescriptor::TYPE_BOOL:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				doc.SetData(to_string(reflection->GetRepeatedBool(msg, fd, count)));
			}
		}
		else
		{
			doc.SetData(to_string(reflection->GetBool(msg, fd)));
		}

		break;

		// UTF-8 text.
	case FieldDescriptor::TYPE_STRING:
		// Arbitrary byte array.
	case FieldDescriptor::TYPE_BYTES:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				doc.SetData(reflection->GetRepeatedString(msg, fd, count));
			}
		}
		else
		{
			doc.SetData(reflection->GetString(msg, fd));
		}

		break;

		// Tag-delimited message.  Deprecated.
	case FieldDescriptor::TYPE_GROUP:
		// Length-delimited message.
	case FieldDescriptor::TYPE_MESSAGE:
		assert(0);
		return false;
		break;

		// Enum, varint on the wire
	case FieldDescriptor::TYPE_ENUM:
		if(fd->is_repeated())
		{
			for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
			{
				doc.SetData(reflection->GetRepeatedEnum(msg, fd, count)->number());
			}
		}
		else
		{
			doc.SetData(reflection->GetEnum(msg, fd)->number());
		}

		break;
	default:
		assert(0);
		return false;
		break;
	}

	//重新进入tag
	doc.IntoElem();
	return true;
}

static bool proto_msg2xml(const google::protobuf::Message& msg, CMarkup& doc, const std::string& name)
{
	//增加tag
	doc.AddElem(name);
	//进入新增tag
	doc.IntoElem();

	const google::protobuf::Reflection* reflection = msg.GetReflection();
	assert(reflection);
	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	assert(des);
	for(int count = 0; count < des->field_count(); ++count)
	{
		const google::protobuf::FieldDescriptor* fd = des->field(count);
		assert(fd);
		std::string key = fd->name();
		//没有设置的非repeated字段不组装进xml
		if(key == INTER_PROTO_CMARKUP_NAME || (!fd->is_repeated() && !reflection->HasField(msg, fd)))
		{
			continue;
		}
		
		if(is_attribute(key))
		{
			if(!proto_fd2xml_attr(msg, fd, doc, get_attribute_name(key)))
			{
				return false;
			}
		}
		else if(is_text(key))
		{
			if(!proto_fd2xml_text(msg, fd, doc))
			{
				return false;
			}
		}
		else
		{
			switch(fd->type())
			{
				// double, exactly eight bytes on the wire.
			case FieldDescriptor::TYPE_DOUBLE:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						doc.AddElem(key, to_string(reflection->GetRepeatedDouble(msg, fd, count)));
					}
				}
				else
				{
					doc.AddElem(key, to_string(reflection->GetDouble(msg, fd)));
				}

				break;

				// float, exactly four bytes on the wire.
			case FieldDescriptor::TYPE_FLOAT:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						doc.AddElem(key, to_string(reflection->GetRepeatedFloat(msg, fd, count)));
					}
				}
				else
				{
					doc.AddElem(key, to_string(reflection->GetFloat(msg, fd)));
				}

				break;

				// int32, varint on the wire.  Negative numbers
				// take 10 bytes.  Use TYPE_SINT32 if negative
				// values are likely.
			case FieldDescriptor::TYPE_INT32:
				// int32, exactly four bytes on the wire
			case FieldDescriptor::TYPE_SFIXED32:
				// int32, ZigZag-encoded varint on the wire
			case FieldDescriptor::TYPE_SINT32:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						doc.AddElem(key, to_string(reflection->GetRepeatedInt32(msg, fd, count)));
					}
				}
				else
				{
					doc.AddElem(key, to_string(reflection->GetInt32(msg, fd)));
				}

				break;

				// uint32, varint on the wire
			case FieldDescriptor::TYPE_UINT32:
				// uint32, exactly four bytes on the wire.
			case FieldDescriptor::TYPE_FIXED32:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						doc.AddElem(key, to_string(reflection->GetRepeatedUInt32(msg, fd, count)));
					}
				}
				else
				{
					doc.AddElem(key, to_string(reflection->GetUInt32(msg, fd)));
				}

				break;

				// int64, varint on the wire.  Negative numbers
				// take 10 bytes.  Use TYPE_SINT64 if negative
				// values are likely.
			case FieldDescriptor::TYPE_INT64:
				// int64, exactly eight bytes on the wire
			case FieldDescriptor::TYPE_SFIXED64:
				// int64, ZigZag-encoded varint on the wire
			case FieldDescriptor::TYPE_SINT64:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						doc.AddElem(key, to_string(reflection->GetRepeatedInt64(msg, fd, count)));
					}
				}
				else
				{
					doc.AddElem(key, to_string(reflection->GetInt64(msg, fd)));
				}

				break;

				// uint64, varint on the wire.
			case FieldDescriptor::TYPE_UINT64:
				// uint64, exactly eight bytes on the wire.
			case FieldDescriptor::TYPE_FIXED64:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						doc.AddElem(key, to_string(reflection->GetRepeatedUInt64(msg, fd, count)));
					}
				}
				else
				{
					doc.AddElem(key, to_string(reflection->GetUInt64(msg, fd)));
				}

				break;

				// bool, varint on the wire.
			case FieldDescriptor::TYPE_BOOL:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						doc.AddElem(key, to_string(reflection->GetRepeatedBool(msg, fd, count)));
					}
				}
				else
				{
					doc.AddElem(key, to_string(reflection->GetBool(msg, fd)));
				}

				break;

				// UTF-8 text.
			case FieldDescriptor::TYPE_STRING:
				// Arbitrary byte array.
			case FieldDescriptor::TYPE_BYTES:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						doc.AddElem(key, reflection->GetRepeatedString(msg, fd, count));
					}
				}
				else
				{
					doc.AddElem(key, reflection->GetString(msg, fd));
				}

				break;

				// Tag-delimited message.  Deprecated.
			case FieldDescriptor::TYPE_GROUP:
				// Length-delimited message.
			case FieldDescriptor::TYPE_MESSAGE:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						if(!proto_msg2xml(reflection->GetRepeatedMessage(msg, fd, count), doc, key))
						{
							return false;
						}
					}
				}
				else
				{
					//宏用于解决宏定义与函数名冲突
#pragma push_macro("GetMessage")
#undef GetMessage
					if(!proto_msg2xml(reflection->GetMessage(msg, fd), doc, key))
					{
						return false;
					}

#pragma pop_macro("GetMessage")
				}

				break;

				// Enum, varint on the wire
			case FieldDescriptor::TYPE_ENUM:
				if(fd->is_repeated())
				{
					for(int count = 0; count < reflection->FieldSize(msg, fd); ++count)
					{
						doc.AddElem(key, reflection->GetRepeatedEnum(msg, fd, count)->number());
					}
				}
				else
				{
					doc.AddElem(key, reflection->GetEnum(msg, fd)->number());
				}

				break;
			default:
				assert(0);
				return false;
				break;
			}
		}
	}
	
	doc.OutOfElem();
	return true;
}

bool proto2cmarkup(const google::protobuf::Message& msg, std::string& xml, cmarkup_type type/* = CMARKUP_GB2312*/)
{
	CMarkup doc;
	if(type == CMARKUP_GB2312)
	{
		doc.SetDoc("<?xml version=\"1.0\" encoding=\"gb2312\"?>\r\n");			//设置xml头
	}
	else if(type == CMARKUP_UTF8)
	{
		doc.SetDoc("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");			//设置xml头
	}

	const google::protobuf::Descriptor* des = msg.GetDescriptor();
	const google::protobuf::FieldDescriptor* fd = des->FindFieldByName(INTER_PROTO_CMARKUP_NAME);
	if(!fd || fd->is_repeated() || (fd->type() != FieldDescriptor::TYPE_STRING && fd->type() != FieldDescriptor::TYPE_BYTES))
	{
		assert(0);
		return false;
	}

	const google::protobuf::Reflection* reflection = msg.GetReflection();
	if(!proto_msg2xml(msg, doc, reflection->GetString(msg, fd)))
	{
		return false;
	}

	xml = doc.GetDoc();
	return true;
} 



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值