Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1680825
  • 博文数量: 584
  • 博客积分: 13857
  • 博客等级: 上将
  • 技术积分: 11883
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-16 09:34

分类: LINUX

2010-11-12 12:03:51

    阅读开源项目FBReader 程序源码的时候,发现ZLXMLReader在解析XML时,采用了一种特殊的机制。解析时,进入XML TAG和退出XML TAG时,C++类ZLXMLReader的startElementHandler 和 endElementHandler 类成员函数被eXpat (C语言实现的XML解析库) 函数不停的调用。我仔细查看了一下,并仿写了一个类似的机制。

   

//CB.h

 

  1. #ifndef _CB_H_  
  2. #define _CB_H_  
  3.   
  4. #include "CStyle.h"  
  5.   
  6. class CallBackUserData;  
  7.   
  8. class CallBackInternal  
  9. {  
  10. public:  
  11.     CallBackInternal(CallBackUserData &a_C_UserData);  
  12.     virtual ~CallBackInternal();  
  13.   
  14.     void Do();  
  15.   
  16. private:  
  17.     static void StartSthFunc( void *a_pv_UserData, const char *a_psz_Name );  
  18.     static void EndSthFunc( void *a_pv_UserData, const char *a_psz_Name );  
  19.   
  20. private:  
  21.     CStyleStruct_S * m_S_Parser;  
  22.     CallBackUserData &m_C_UserData;  
  23. };  
  24.   
  25. class CallBackUserData  
  26. {  
  27. public:  
  28.     CallBackUserData();  
  29.     ~CallBackUserData();  
  30. public:  
  31.     void StartSth( const char * a_psz_Name  );  
  32.     void EndSth( const char * a_psz_Name  );  
  33.     void Do();  
  34. private:  
  35.     CallBackInternal *m_C_Internal;  
  36. };  
  37.   
  38. #endif  
 

//CB.cpp

 

  1. #include   
  2. #include "CB.h"  
  3.   
  4. CallBackInternal::CallBackInternal(CallBackUserData &a_C_UserData) : m_C_UserData(a_C_UserData)  
  5. {  
  6.     m_S_Parser = CreateParser();  
  7.     SetUserData(m_S_Parser, &m_C_UserData );  
  8.     SetStartHandler(m_S_Parser, StartSthFunc);  
  9.     SetEndHandler(m_S_Parser, EndSthFunc );  
  10. }  
  11.   
  12. CallBackInternal::~CallBackInternal()  
  13. {  
  14.     FreeParser(m_S_Parser);  
  15. }  
  16.   
  17. void CallBackInternal::StartSthFunc( void *a_pv_UserData, const char *a_psz_Name )  
  18. {  
  19.     CallBackUserData &reader = *(CallBackUserData*)a_pv_UserData;  
  20.     reader.StartSth(a_psz_Name);  
  21.       
  22.   
  23. }  
  24.   
  25. void CallBackInternal::EndSthFunc( void *a_pv_UserData, const char *a_psz_Name )  
  26. {  
  27.     CallBackUserData &reader = *(CallBackUserData*)a_pv_UserData;  
  28.     reader.EndSth(a_psz_Name);  
  29. }  
  30.   
  31. void CallBackInternal::Do()  
  32. {  
  33.     DoSth(m_S_Parser);  
  34. }  
  35.   
  36. //////////////////////////////////////////////////////////////////////////  
  37.   
  38.   
  39. CallBackUserData::CallBackUserData()  
  40. {  
  41.     m_C_Internal = new CallBackInternal(*this);  
  42. }  
  43.   
  44. CallBackUserData::~CallBackUserData()  
  45. {  
  46.     if (0==m_C_Internal)  
  47.     {  
  48.         delete m_C_Internal;  
  49.         m_C_Internal = 0;  
  50.     }  
  51. }  
  52.   
  53. void CallBackUserData::StartSth( const char * a_psz_Name )  
  54. {  
  55.     printf("CallBackUserData::StartSth()\n");  
  56.     printf("C库中解析出来的数据作为参数: %s\n",a_psz_Name);  
  57. }  
  58.   
  59. void CallBackUserData::EndSth( const char * a_psz_Name  )  
  60. {  
  61.     printf("CallBackUserData::EndSth()\n");  
  62.     printf("C库中解析出来的数据作为参数: %s\n",a_psz_Name);  
  63. }  
  64.   
  65. void CallBackUserData::Do()  
  66. {  
  67.     m_C_Internal->Do();  
  68. }  

//CStyle.h

 

  1. #ifndef _C_STYLE_H_  
  2. #define _C_STYLE_H_  
  3.   
  4. #include   
  5. #include   
  6.   
  7. #ifdef __cplusplus  
  8. extern "C"  
  9. {  
  10. #endif  
  11.   
  12. typedef void (*StartHandler)( void *a_pv_UserData, const char *a_psz_Name );  
  13. typedef void (*EndHandler)( void *a_pv_UserData, const char *a_psz_Name );  
  14.   
  15. typedef struct _CStyleStruct_S  
  16. {  
  17.     void *m_pv_UserData;  
  18.     StartHandler m_p_StartHandler;  
  19.     EndHandler m_p_EndHandler;  
  20. }CStyleStruct_S;  
  21.   
  22. CStyleStruct_S *CreateParser();  
  23. void SetUserData(CStyleStruct_S* a_S_This, void *a_pv_UserData);  
  24. void SetStartHandler(CStyleStruct_S* a_S_This, void *a_pv_FuncPtr);  
  25. void SetEndHandler(CStyleStruct_S* a_S_This, void *a_pv_FuncPtr);  
  26. void DoSth(CStyleStruct_S* a_S_This);  
  27. void FreeParser(CStyleStruct_S *a_S_This);  
  28.   
  29. #ifdef __cplusplus  
  30. }  
  31. #endif  
  32.   
  33. #endif  

//CStyle.c

 

  1. #include "CStyle.h"  
  2.   
  3. #define userData        (a_S_This->m_pv_UserData)  
  4. #define startHanler (a_S_This->m_p_StartHandler)  
  5. #define endHanler   (a_S_This->m_p_EndHandler)  
  6.   
  7. CStyleStruct_S *CreateParser()  
  8. {  
  9.     CStyleStruct_S *t_S_p = (CStyleStruct_S *)malloc(sizeof(CStyleStruct_S));  
  10.     //if ( NULL != t_S_p)  
  11.     //{  
  12.     //  memset( t_S_p, 0, sizeof(CStyleStruct_S));  
  13.     //}  
  14.     return t_S_p;  
  15. }  
  16.   
  17. void SetUserData(CStyleStruct_S* a_S_This, void *a_pv_UserData)  
  18. {  
  19.     userData = a_pv_UserData;  
  20. }  
  21.   
  22. void SetStartHandler(CStyleStruct_S* a_S_This, void *a_pv_FuncPtr)  
  23. {  
  24.     startHanler = a_pv_FuncPtr;  
  25. }  
  26.   
  27. void SetEndHandler(CStyleStruct_S* a_S_This, void *a_pv_FuncPtr)  
  28. {  
  29.     endHanler = a_pv_FuncPtr;  
  30. }  
  31.   
  32. void DoSth(CStyleStruct_S* a_S_This)  
  33. {  
  34.     startHanler(userData, "start_");  
  35.     endHanler(userData, "end_");  
  36. }  
  37.   
  38. void FreeParser(CStyleStruct_S *a_S_This)  
  39. {  
  40.     if (a_S_This)  
  41.     {  
  42.         free(a_S_This);  
  43.         a_S_This = 0;  
  44.     }  
  45. }  

main函数中这样调用:

  1. #include   
  2. #include   
  3. #include "CB.h"  
  4.   
  5.   
  6. int _tmain(int argc, _TCHAR* argv[])  
  7. {  
  8.     CallBackUserData reader;  
  9.     reader.Do();  
  10.     system("pause");  
  11.     return 0;  
  12. }  

调用顺序:

1. 当调用 main函数中的 CallBackUserData reader;    reader.Do();

2. reader.Do(); 调用了CallBackInternal->Do(); 

3. 中介者CallBackInternal 的Do函数,又调用了 C语言的 函数 DoSth(m_S_Parser);

4. DoSth 又以函数指针的形式,调用了 CallBackInternal 类的静态成员函数StartSthFunc和EndSthFunc,并以参数形式传递在C库中解析出的内容到这两个静态函数。

5. 在这两个静态函数中,又调用了CallBackUserData 的 StartSth和EndSth。

说明:

1. 类CallBackUserData是一个用户自定义的数据结构,这里以类的形式描述。

2. 类CallBackInternal 则是C与C++相互调用的中间者,起到了一个中介的作用。

3. CStyle.h 和 CStyle.cpp中的类则是C风格的方式。

这样一个机制,通过函数指针与静态类成员函数,实现了C与C++的交互,在C中调用C++的类成员函数,即相当于在C库的DoSth中,调用了 CallBackUserData 中的StartSth 和 EndSth, C库解析的内容,则作为 StartSth 和 EndSth 的参数。

CallBackUserData 的函数 Do(); 相当于绕了一个弯子,进入了C函数库,与直接调用CallBackUserData::StartSth() 与CallBackUserData::EndSth()的结果是一样的。

实际应用:

eXpat 和 FBReader中的ZLXMLReader 类的这种机制,使得eXpat库解析到一个 的XML标签时,进入解析时,调用StartSth (startElementHandler), 退出解析时,调用EndSth (endElementHandler), 而且 BTN, id=100 均与 参数形式被传出到 StartSth, EndSth 中, 使用者就可以知道是解析到了什么。

我们将CallBackUserData (ZLXMLReader ) 作为基类, 并派生相应的类。并在派生类中重载 StartSth (startElementHandler), EndSth (endElementHandler), 就可以利用XML配置派生类相应的属性。

使用这种机制,就将eXpat库进行了包裹,方便了使用,是一种很灵巧的方法。

运行结果:

运行结果

呃。。。,有点不知所云。(表达能力欠缺啊)

阅读(2103) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~