程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 【iOS-cocos2d-X 游戲開發之九】Cocos2dx利用CCSAXParser解析xml數據

【iOS-cocos2d-X 游戲開發之九】Cocos2dx利用CCSAXParser解析xml數據

編輯:關於C語言

 本站文章均為 李華明Himi 原創,轉載務必在明顯處注明:

轉載自黑米GameDev街區】 原文鏈接: http://www.himigame.com/iphone-cocos2dx/694.html

          ☞ 點擊訂閱 ☜
 本博客最新動態!及時將最新博文通知您!

本章Himi給大家分享如何在Cocos2dX中解析xml數據;對於數據存取有很多方式,流文件,plist,xml等,那麼為了跨平台更好的支持,Himi想到之前寫的CCUserDefault 存儲數據一節,Cocos2dx自帶的存儲類,一旦存入數據都會以xml格式進行保存,適用於iOS、Android等平台,所以這裡Himi使用xml進行游戲的一些數據錄入  = =.. 另外一方面Himi本章節也是基於Cocos2dx引擎代碼進行的一次簡單對xml數據解析的封裝;

為了更保險的去考慮跨平台,所以對於xml存儲這塊的解析,也做了些搜索,最後發現王哥(王哲-cocos2dx引擎作者)也有給我們提示過,內容如下:

  1. cocos2dx裡面集成了libxml2,ios上會調用sdk裡面內置的, 
  2. android和win32上則帶了已經編譯好的靜態/動態庫。 
  3. 你可以參考CCSAXParser裡面的代碼來使用libxml2 
 

那麼既然如此,就對Cocos2dx引擎源碼的CCSAXParser類進行了剖析,那麼這裡Himi,先給出代碼,然後再詳細講解下:

Himi封裝的HXmlParse類:

  1. HXmlParse.h 
  2.   
  3. // 
  4. //  HXmlParse.h 
  5. //  HAnimation 
  6. // 
  7. //  Created by Himi on 12-3-22. 
  8. //  Copyright (c) 2012年 Augustimpression. All rights reserved. 
  9. // 
  10.   
  11. #ifndef HAnimation_HXmlParse_h 
  12. #define HAnimation_HXmlParse_h 
  13.   
  14. #include "cocos2d.h" 
  15. #include "CCSAXParser.h" 
  16. #include "CCObject.h" 
  17. #include "CCMutableDictionary.h" 
  18.   
  19. using namespace cocos2d; 
  20.   
  21. class CC_DLL HXmlParse :public CCObject, public CCSAXDelegator 
  22. { 
  23.   
  24. public: 
  25.   
  26.     static HXmlParse * parserWithFile(const char *tmxFile); 
  27.   
  28.     bool initHXmlParse(const char* xmlName); 
  29.   
  30.     //  使用 CCSAXDelegator 重寫3個回調函數 
  31.   
  32.     void startElement(void *ctx, const char *name, const char **atts); 
  33.   
  34.     void endElement(void *ctx, const char *name); 
  35.   
  36.     void textHandler(void *ctx, const char *ch, int len); 
  37.   
  38.     std::string root_name;  
  39.   
  40.     bool isJumpHeadData; 
  41.   
  42.     CCMutableDictionary<std::string,CCString*> *mDic; 
  43.   
  44. private: 
  45.   
  46.     std::string startXmlElement;//用來記錄每個key前字段 
  47.   
  48.     std::string endXmlElement;//用來記錄每個key後字段 
  49.   
  50.     std::string currString;//記錄每個value的值 
  51.   
  52. }; 
  53.   
  54. #endif  
  55. HXmlParse.cpp 
  56.   
  57. // 
  58. //  HXmlParse.cpp 
  59. //  HAnimation 
  60. // 
  61. //  Created by Himi on 12-3-22. 
  62. //  Copyright (c) 2012年 Augustimpression. All rights reserved. 
  63. // 
  64.   
  65. #include "HXmlParse.h" 
  66. #include "CCSAXParser.h" 
  67.   
  68. HXmlParse * HXmlParse::parserWithFile(const char *tmxFile) 
  69. { 
  70.     HXmlParse *pRet = new HXmlParse(); 
  71.     if(pRet->initHXmlParse(tmxFile)) 
  72.     { 
  73.         pRet->autorelease(); 
  74.         return pRet; 
  75.     } 
  76.     CC_SAFE_DELETE(pRet); 
  77.     return NULL; 
  78. } 
  79.   
  80. bool HXmlParse::initHXmlParse(const char* xmlName) 
  81.   
  82. { 
  83.   
  84.     mDic = new CCMutableDictionary<std::string,CCString*>(); 
  85.   
  86.     CCSAXParser _par;   
  87.   
  88.     if (false == _par.init("UTF-8") ) 
  89.   
  90.     { 
  91.         CCLog("-----請使用utf-8格式!"); 
  92.         return false; 
  93.     } 
  94.     _par.setDelegator(this); 
  95.     const char* _path =CCFileUtils::fullPathFromRelativePath(xmlName); 
  96.     return _par.parse(_path); 
  97.   
  98. } 
  99.   
  100. //回調函數 
  101.   
  102. void HXmlParse::startElement(void *ctx, const char *name, const char **atts) 
  103.   
  104. {    
  105.   
  106.     CC_UNUSED_PARAM(ctx); 
  107.   
  108.     startXmlElement = (char*)name; 
  109.     if(!isJumpHeadData){//跳過數據頭 
  110.         CCLog("------跳過root name"); 
  111.         isJumpHeadData=true; 
  112.         root_name=startXmlElement; 
  113.         return; 
  114.     } 
  115.   
  116. //    CCLog("-startElement----%s",startXmlElement.c_str()); 
  117.   
  118. } 
  119.   
  120. void HXmlParse::endElement(void *ctx, const char *name) 
  121.   
  122. { 
  123.     CC_UNUSED_PARAM(ctx); 
  124.   
  125.     endXmlElement = (char*)name; 
  126.     if(endXmlElement==root_name){//數據尾 
  127.         CCLog("讀取xml結束"); 
  128.         isJumpHeadData=false; 
  129.         root_name=""; 
  130.         return; 
  131.     } 
  132.   
  133. //    CCLog("-endElement----%s",endXmlElement.c_str()); 
  134. } 
  135. //鍵值對的結束字段 
  136. void HXmlParse::textHandler(void *ctx, const char *ch, int len) 
  137. { 
  138.   
  139.     CC_UNUSED_PARAM(ctx); 
  140.     currString=string((char*)ch,0,len); 
  141.     CCString *ccStr =new CCString();//備注3 
  142.     ccStr->m_sString=currString; 
  143.     if(root_name!=""){ 
  144.          mDic->setObject(ccStr,startXmlElement); 
  145.         CCLog("-----key:%s, value:%s",startXmlElement.c_str(),mDic->objectForKey(startXmlElement)->m_sString.c_str()); 
  146.     } 
  147.   
  148. //    CCLog("-textHandler----%s",currString.c_str()); 
  149.   
  150. } 
 

OK,代碼呢我們先從.h中來說,首先我們使用CCSAXDelegator,為了讓CCSAXParser解析數據後將數據回調給如下三個函數:

  1. //  使用 CCSAXDelegator 重寫3個回調函數 
  2.   
  3.    void startElement(void *ctx, const char *name, const char **atts); 
  4.   
  5.    void endElement(void *ctx, const char *name); 
  6.   
  7.    void textHandler(void *ctx, const char *ch, int len); 
 

startElement   函數解析的是xml的每個key前字段

textHandler  函數解析出來的是xml每個key對應的value值

endElement   函數解析出來的是xml的每個key後字段

這裡Himi隨便寫了一個xml來做測試,himi.xml,如下:

  1. <?xml version="1.0" encoding="utf-8"?><himiTestData><key1>1000</key1><key2>娃哈哈</key2><key3>82.3</key3><key4>4000</key4><key5>himi</key5><key6>true</key6></himiTestData> 

那麼CCSAXParser類解析第一次回調 startElement 是讀取的是root namexml數據頭標識名稱->“<himiTestData>”),然後才讀取正式數據key和value,最後讀取的也是xml數據尾標識名稱“</himiTestData>”

當然在Himi封裝的HXmlParse類中對於數據標識的讀取都跳過了,使用變量isJumpHeadData來處理的;

其他的都很容易沒有什麼可說的,主要要說還有一點就是關於CCMutableDictionary的使用,對於此類主要結構是形成map&NSMutableDictionary類似是個鍵值對容器,key-value;那麼使用時候要注意4點:

1.  比如Himi解析數據後都會默認將key和value數據存放在CCMutableDictionary中,那麼這裡我肯定傳入的是兩個string,但是細心的童鞋會發現代碼中第二個並不是std::string,而是CCString對象,嗯 沒錯,CCMutableDictionary要求傳入的是CCObject對象而不是基本類型!CCString中有m_sString這個屬性,所以轉換起來也是很方便的;

2. 使用CCMutableDictionary進行添加數據setObject的時候要注意此函數的兩個參數:

  1. bool setObject(_ValueT pObject, const _KeyT& key) 
  2.     { 
  3.         pair<CCObjectMapIter, bool > pr; 
  4.   
  5.         pr = m_Map.insert( Int_Pair(key, pObject) ); 
  6.   
  7.         if(pr.second == true) 
  8.         { 
  9.             pObject->retain(); 
  10.             return true; 
  11.         } 
  12.   
  13.         return false; 
  14.     } 
 

上面這個是cocos2dx引擎中源碼中setObject函數實現代碼,這裡可以很清晰的看到,第一個參數表示《CCObject》,第二個參數才是《Key》!這點對於之前做過java開發的我來說比較郁悶,因為一般都是key在第一個參數。。。。。

3. 請大家仔細看HXmlParse.cpp類中的備注3 ,當你使用CCMutableDictionary的setObject函數的時候,務必要注意,此函數的存入的CCObject參數,引擎中實現代碼是對你這個CCObject進行retain()的一個內存地址引用!也就是說這裡不要使用一個成員變量來使用,否則你從CCMutableDictionary取出來的數據全部是你最後一個CCObject數據!

4. CCMutableDictionary是cocos2d-x自己封裝的類,功能類似NSMutableDictionary。但是Himi通過測試發現!它有一點和NSMutableDictionary是不一樣的。NSMutableDictionary的setObjectForKey方法是:如果發現這個key已經存在於字典中的時候,它會自動用新的object覆蓋掉原有的object。而CCMutableDictionary由於它是使用map實現的字典功能,而在map裡面,如果key已存在,是不會用新的object覆蓋掉原有object的。在使用CCMutableDictionary的時候需要特別注意這一點。

HXmlParse解析xml類使用方法很簡單:

  1. #include "HXmlParse.h" 
  2.   
  3. HXmlParse::parserWithFile("himi.xml"); 
 

然後Himi為了證實此解析類在Android也可以正常運行,那麼這裡Himi將讀出的數據展示在畫面上,iOS運行截圖如下:

 

 

 

本文出自 “李華明Himi” 博客,請務必保留此出處http://xiaominghimi.blog.51cto.com/2614927/841867

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved