XML 序列化器
最近試圖編寫一個(gè)C++的XML序列化器,目前實(shí)現(xiàn)了一些基本的功能。為了開發(fā)一個(gè)XML序列化器,首先要有XML讀取器(Reader)和書寫器(Writer)。我實(shí)現(xiàn)了兩個(gè)簡單的XML Reader和Writer:

class SimpleXmlElement


{

public:

enum NodeType


{

UNKNOWN,

ATTRIBUTE,

ELEMENT,

ENDOFELEMENT

};


private:

friend class SimpleXmlReader;


public:

NodeType GetType() const;

const String & GetName() const;

bool IsEmptyElement() const;


protected:

void Reset(NodeType type, const String & name, bool isEmptyElement);


private:

NodeType m_type;

String m_name;

bool m_isEmptyElement;

};


class SimpleXmlAttribute: public SimpleXmlElement


{

friend class SimpleXmlReader;


public:

const String & GetValue() const;


protected:

void Reset(const String & name, const String & val);


private:

String m_val;

};


class SimpleXmlReader


{

public:

SimpleXmlReader();

virtual ~SimpleXmlReader();


virtual void Open(IStream * stream, ICharsetEncoding * encoding = NULL)

virtual void Open(const void * buffer, SIZE_TYPE length, ICharsetEncoding * encoding = NULL);

virtual void Open(const void * buffer, int offset, SIZE_TYPE length, ICharsetEncoding * encoding = NULL);


virtual bool IsEndOfStream() const;

virtual const SimpleXmlElement * GetNextElement();

virtual const SimpleXmlAttribute * GetNextAttribute();

virtual const String GetElementInnerText();


};


//-------------------------------------------------------------------------------------------

class SimpleXmlWriter


{

public:

SimpleXmlWriter();

virtual ~SimpleXmlWriter();


virtual void Open(ICharsetEncoding * encoding = NULL);

virtual void Open(IStream * stream, ICharsetEncoding * encoding = NULL);


virtual void EnterElement(const String & element);

virtual void AddAttribute(const String & attribute, const String & value);

virtual void SetElementInnerText(const String & text);

virtual void LeaveElement();


virtual const void * GetBuffer();

virtual SIZE_TYPE GetLength();

};

在這兩個(gè)類中,IStream是保存數(shù)據(jù)的流接口,ICharsetEncoding是用于字符集轉(zhuǎn)換的編碼接口。
使用這兩個(gè)類就可以進(jìn)行XML序列化了。
class XmlSerializer;
struct IXmlSerializable
{
virtual void Serialize(XmlSerializer * serializer, bool serialize) = 0;
};
class XmlTree;
class XmlSerializer
{
public:
XmlSerializer();
virtual ~XmlSerializer();
virtual void OpenSerializer(IStream * stream, ICharsetEncoding * encoding = NULL);
virtual void OpenDeserializer(IStream * stream, ICharsetEncoding * encoding = NULL);
virtual void Close();
virtual void SerializeElement(const String & className, const String & elementName, bool var);
virtual void SerializeElement(const String & className, const String & elementName, int var);
virtual void SerializeElement(const String & className, const String & elementName, const String & var);
virtual void SerializeElement(const String & className, const String & elementName, IXmlSerializable & var);
virtual void SerializeAttribute(const String & className, const String & elementName, const String & attributeName, bool var);
virtual void SerializeAttribute(const String & className, const String & elementName, const String & attributeName, int var);
virtual void SerializeAttribute(const String & className, const String & elementName, const String & attributeName, const String & var);
virtual void DeserializeElement(const String & className, const String & elementName, bool &var);
virtual void DeserializeElement(const String & className, const String & elementName, int & var);
virtual void DeserializeElement(const String & className, const String & elementName, String & var);
virtual void DeserializeElement(const String & className, const String & elementName, IXmlSerializable & var);
virtual void DeserializeAttribute(const String & className, const String & elementName, const String & attributeName, bool & var);
virtual void DeserializeAttribute(const String & className, const String & elementName, const String & attributeName, int & var);
virtual void DeserializeAttribute(const String & className, const String & elementName, const String & attributeName, String & var);
};
#define BEGIN_XML_SERIALIZER_BASE(className, baseClassName) \
virtual void Serialize(XmlSerializer * serializer, bool serialize) \
{ \
const String __className = TEXT(#className); \
\
if (IsTypeDerivedFrom<baseClassName, IXmlSerializable>::Yes) \
{ \
baseClassName::Serialize(serializer, serialize); \
}
#define BEGIN_XML_SERIALIZER(className) \
virtual void Serialize(XmlSerializer * serializer, bool serialize) \
{ \
const String __className = TEXT(#className);
#define END_XML_SERIALIZER() \
}
#define XML_ELEMENT(var) \
if (serialize) \
{ \
serializer->SerializeElement(__className, TEXT(#var), var); \
} \
else \
{ \
serializer->DeserializeElement(__className, TEXT(#var), var); \
}
#define XML_ATTRIBUTE(element, var) \
if (serialize) \
{ \
serializer->SerializeAttribute(__className, TEXT(#element), TEXT(#var), var); \
} \
else \
{ \
serializer->DeserializeAttribute(__className, TEXT(#element), TEXT(#var), var); \
}
有一個(gè)模板類 IsTypeDerivedFrom<T, U>用于判斷類型T是否從類型U派生。如果是,那么Yes=1,否則Yes=0。
為了序列化一個(gè)類,首先從 IXmlSerializable 接口派生(實(shí)際上如果這個(gè)類不作為其它序列化類的基類的化,也可以不用從該接口派生),然后使用 BEGIN_XML_SERIALIZER (對(duì)于單獨(dú)的類)或者 BEGIN_XML_SERIALIZER_BASE(對(duì)于需要序列化基類的情況)開始定義序列化器。例如:
class ClassA: public IXmlSerializable
{
public:
BEGIN_XML_SERIALIZER(ClassA)
XML_ELEMENT(m_data)
XML_ATTRIBUTE(m_data, m_value)
XML_ELEMENT(m_bool)
XML_ELEMENT(m_s)
END_XML_SERIALIZER();
ClassA()
: m_data(0),
m_value(1),
m_bool(false),
m_s(TEXT("Hello"))
{
}
void Reset()
{
m_data = -1;
m_value = 0;
m_bool = true;
m_s = TEXT("");
}
private:
int m_data;
int m_value;
bool m_bool;
String m_s;
};
class ClassC: public ClassA
{
public:
BEGIN_XML_SERIALIZER_BASE(ClassC, ClassA)
XML_ELEMENT(m_data)
XML_ATTRIBUTE(m_data, m_value)
XML_ELEMENT(m_bool)
XML_ELEMENT(m_s)
XML_ELEMENT(m_a)
END_XML_SERIALIZER();
ClassC()
: m_data(0),
m_value(1),
m_bool(false),
m_s(TEXT("Hello"))
{
}
void Reset()
{
m_data = -1;
m_value = 0;
m_bool = true;
m_s = TEXT("");
}
private:
int m_data;
int m_value;
bool m_bool;
String m_s;
ClassA m_a;
};
執(zhí)行下面的代碼:
XmlSerializer serializer;
MemoryStream ms;
ms.Open();
serializer->OpenSerializer(&ms);
ClassC c;
c.Serialize(&serializer, true);
serializer.Close();
const char * buf = static_cast<const char *>(ms.GetBuffer());
這樣 buf 中就包含了序列化以后的XML文本,如下:
<SerializeData>
<ClassA>
<m_bool>false</m_bool>
<m_data m_value="1">0</m_data>
<m_s>Hello</m_s>
</ClassA>
<ClassC>
<m_a>
<ClassA>
<m_bool>false</m_bool>
<m_data m_value="1">0</m_data>
<m_s>Hello</m_s>
</ClassA>
</m_a>
<m_bool>false</m_bool>
<m_data m_value="1">0</m_data>
<m_s>Hello</m_s>
</ClassC>
</SerializeData>
實(shí)際的序列化后的文本是不包含縮進(jìn)的,上面這樣只是為了便于瀏覽。
使用 c.Serialize(&serializer, false) 可以執(zhí)行反序列化,即從 XML 文本生成對(duì)應(yīng)的對(duì)象。
【限制】
目前尚沒有實(shí)現(xiàn)對(duì)數(shù)組的序列化,對(duì)于指針,考慮不做序列化,原因在于涉及到內(nèi)存的分配以及動(dòng)態(tài)多態(tài)等問題不是很好解決。