xml 与 protobuf之间的转换

这段代码展示了如何使用C++将TinyXML解析的XML数据转换为protobuf消息,以及将protobuf消息转换回XML。它利用了protobuf的反射API来处理各种字段类型,并支持不同的字符编码。
摘要由CSDN通过智能技术生成
#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())
						{
							reflec
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值