返回   cpper编程论坛 > Blog > Innocentius
注册账号 论坛帮助 会员列表 日历事件 搜索 今日新帖 标记版面已读

为这篇文章评分

C++ XML 序列化器

发表于 2006-08-04 11:46 AM 作者: Innocentius
XML 序列化器
最近试图编写一个C++的XML序列化器,目前实现了一些基本的功能。为了开发一个XML序列化器,首先要有XML读取器(Reader)和书写器(Writer)。我实现了两个简单的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();
    };

在这两个类中,IStream是保存数据的流接口,ICharsetEncoding是用于字符集转换的编码接口。
使用这两个类就可以进行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); \
        }
有一个模板类 IsTypeDerivedFrom<T, U>用于判断类型T是否从类型U派生。如果是,那么Yes=1,否则Yes=0。
为 了序列化一个类,首先从 IXmlSerializable 接口派生(实际上如果这个类不作为其它序列化类的基类的化,也可以不用从该接口派生),然后使用 BEGIN_XML_SERIALIZER (对于单独的类)或者 BEGIN_XML_SERIALIZER_BASE(对于需要序列化基类的情况)开始定义序列化器。例如:

代码:
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;
};
执行下面的代码:


代码:
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>
实际的序列化后的文本是不包含缩进的,上面这样只是为了便于浏览。
使用 c.Serialize(&serializer, false) 可以执行反序列化,即从 XML 文本生成对应的对象。
【限制】
目前尚没有实现对数组的序列化,对于指针,考虑不做序列化,原因在于涉及到内存的分配以及动态多态等问题不是很好解决。
评论 2 Email文章
评论总数 2

评论

旧
combine MFC style with .NET style, typical MS style,
发表于 2008-03-16 08:28 AM 作者: zero zero 当前离线
旧
能给源代码看看吗,因为我最近做个东东,需要这方面的知识。
发表于 2008-03-16 08:30 AM 作者: hytjfxk@gmail.com
发表评论 发表评论
作者为 Innocentius 的最新文章

所有时间均为格林尼治时间 +9。现在的时间是 01:18 PM


Powered by vBulletin® 版本 3.7.0
版权所有 ©2000 - 2008,Jelsoft Enterprises Ltd.
(C) Copy Right All Right Reserved 2001 - 2007

Search Engine Friendly URLs by vBSEO 3.1.0