#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