zoukankan      html  css  js  c++  java
  • 【iOS-cocos2d-X 游戏开发之九】Cocos2dx利用CCSAXParser解析xml数据&CCMutableDictionary使用与注意!

    本站文章均为 李华明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
    2
    3
    cocos2dx里面集成了libxml2,ios上会调用sdk里面内置的,
    android和win32上则带了已经编译好的静态/动态库。
    你可以参考CCSAXParser里面的代码来使用libxml2

    那么既然如此,就对Cocos2dx引擎源码的CCSAXParser类进行了剖析,那么这里Himi,先给出代码,然后再详细讲解下:

    Himi封装的HXmlParse类:

    1
    2
    3
    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
    1
    2
    3
    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
    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
    //  HAnimation
    //
    //  Created by Himi on 12-3-22.
    //  Copyright (c) 2012年 Augustimpression. All rights reserved.
    //
     
    #include "HXmlParse.h"
    #include "CCSAXParser.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)
     
    {
        CC_UNUSED_PARAM(ctx);
     
        endXmlElement = (char*)name;
        if(endXmlElement==root_name){//数据尾
            CCLog("读取xml结束");
            isJumpHeadData=false;
            root_name="";
            return;
        }
     
    //    CCLog("-endElement----%s",endXmlElement.c_str());
    }
    //键值对的结束字段
    void HXmlParse::textHandler(void *ctx, const char *ch, int len)
    {
     
        CC_UNUSED_PARAM(ctx);
        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解析数据后将数据回调给如下三个函数:

    1
    2
    3
    4
    5
    6
    7
    //  使用 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);

    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 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的时候要注意此函数的两个参数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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类使用方法很简单:

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

    然后Himi为了证实此解析类在Android也可以正常运行,那么这里Himi将读出的数据展示在画面上,iOS运行截图如下:

     

     

  • 相关阅读:
    socket的使用一
    logging模块
    configparser模块
    python中read() readline()以及readlines()用法
    hashlib
    JavaScript中forEach的用法相关
    循环调用是事件绑定中遇到的一些问题
    javascript 中 offsetWidth,clientWidth;offsetHeight,clientHeight的区别
    javascript事件:获取事件对象getEvent函数
    html标签之meta标签
  • 原文地址:https://www.cnblogs.com/hewei2012/p/3361393.html
Copyright © 2011-2022 走看看