天天看點

【IOS-COCOS2D-X 遊戲開發之九】COCOS2DX利用CCSAXPARSER解析XML資料&CCMUTABLEDICTIONARY使用與注意!

本章himi給大家分享如何在cocos2dx中解析xml資料;對于資料存取有很多方式,流檔案,plist,xml等,那麼為了跨平台更好的支援,himi想到之前寫的ccuserdefault 存儲資料一節,cocos2dx自帶的存儲類,一旦存入資料都會以xml格式進行儲存,适用于ios、android等平台,是以這裡himi使用xml進行遊戲的一些資料錄入  = =.. 另外一方面himi本章節也是基于cocos2dx引擎代碼進行的一次簡單對xml資料解析的封裝;

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

1

2

3

cocos2dx裡面內建了libxml2,ios上會調用sdk裡面内置的,

android和win32上則帶了已經編譯好的靜态/動态庫。

你可以參考ccsaxparser裡面的代碼來使用libxml2

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

himi封裝的hxmlparse類:

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

hxmlparse.h

//

//  hxmlparse.h

//  hanimation

//  created by himi on 12-3-22.

//  copyright (c) 2012年 augustimpression. all rights reserved.

#ifndef hanimation_hxmlparse_h

#define hanimation_hxmlparse_h

#include "cocos2d.h"

#include "ccsaxparser.h"

#include "ccobject.h"

#include "ccmutabledictionary.h"

using namespace cocos2d;

class cc_dll hxmlparse :public ccobject, public ccsaxdelegator

{

public:

    static hxmlparse * parserwithfile(const char *tmxfile);

    bool inithxmlparse(const char* xmlname);

    //  使用 ccsaxdelegator 重寫3個回調函數

    void startelement(void *ctx, const char *name, const char **atts);

    void endelement(void *ctx, const char *name);

    void texthandler(void *ctx, const char *ch, int len);

    std::string root_name;

    bool isjumpheaddata;

    ccmutabledictionary<std::string,ccstring*> *mdic;

private:

    std::string startxmlelement;//用來記錄每個key前字段

    std::string endxmlelement;//用來記錄每個key後字段

    std::string currstring;//記錄每個value的值

};

#endif

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

hxmlparse.cpp

//  hxmlparse.cpp

#include "hxmlparse.h"

hxmlparse * hxmlparse::parserwithfile(const char *tmxfile)

    hxmlparse *pret = new hxmlparse();

    if(pret->inithxmlparse(tmxfile))

    {

        pret->autorelease();

        return pret;

    }

    cc_safe_delete(pret);

    return null;

}

bool hxmlparse::inithxmlparse(const char* xmlname)

    mdic = new ccmutabledictionary<std::string,ccstring*>();

    ccsaxparser _par;  

    if (false == _par.init("utf-8") )

        cclog("-----請使用utf-8格式!");

        return false;

    _par.setdelegator(this);

    const char* _path =ccfileutils::fullpathfromrelativepath(xmlname);

    return _par.parse(_path);

//回調函數

void hxmlparse::startelement(void *ctx, const char *name, const char **atts)

{  

    cc_unused_param(ctx);

    startxmlelement = (char*)name;

    if(!isjumpheaddata){//跳過資料頭

        cclog("------跳過root name");

        isjumpheaddata=true;

        root_name=startxmlelement;

        return;

//    cclog("-startelement----%s",startxmlelement.c_str());

void hxmlparse::endelement(void *ctx, const char *name)

    endxmlelement = (char*)name;

    if(endxmlelement==root_name){//資料尾

        cclog("讀取xml結束");

        isjumpheaddata=false;

        root_name="";

//    cclog("-endelement----%s",endxmlelement.c_str());

//鍵值對的結束字段

void hxmlparse::texthandler(void *ctx, const char *ch, int len)

    currstring=string((char*)ch,0,len);

    ccstring *ccstr =new ccstring();//備注3

    ccstr->m_sstring=currstring;

    if(root_name!=""){

         mdic->setobject(ccstr,startxmlelement);

        cclog("-----key:%s, value:%s",startxmlelement.c_str(),mdic->objectforkey(startxmlelement)->m_sstring.c_str());

//    cclog("-texthandler----%s",currstring.c_str());

ok,代碼呢我們先從.h中來說,首先我們使用ccsaxdelegator,為了讓ccsaxparser解析資料後将資料回調給如下三個函數:

//  使用 ccsaxdelegator 重寫3個回調函數

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

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

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

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

<?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 name(xml資料頭辨別名稱->“<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的時候要注意此函數的兩個參數:

bool setobject(_valuet pobject, const _keyt& key)

pair<ccobjectmapiter, bool > pr;

pr = m_map.insert( int_pair(key, pobject) );

if(pr.second == true)

pobject->retain();

return true;

return false;

上面這個是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類使用方法很簡單:

hxmlparse::parserwithfile("himi.xml");

然後himi為了證明此解析類在android也可以正常運作,那麼這裡himi将讀出的資料展示在畫面上,ios運作截圖如下:

【IOS-COCOS2D-X 遊戲開發之九】COCOS2DX利用CCSAXPARSER解析XML資料&CCMUTABLEDICTIONARY使用與注意!
【IOS-COCOS2D-X 遊戲開發之九】COCOS2DX利用CCSAXPARSER解析XML資料&CCMUTABLEDICTIONARY使用與注意!