COCOS2D-3.9 DictMaker分析
2015-12-08 22:11
501 查看
XML 文件的格式:
TEST的 config-example.plist 文件为例:<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>data</key>
<dict>
<key>cocos2d.x.fps</key>
<integer>60</integer>
<key>cocos2d.x.display_fps</key>
<true/>
<key>cocos2d.x.gl.projection</key>
<string>3d</string>
<key>cocos2d.x.texture.pixel_format_for_png</key>
<string>rgba8888</string>
<key>cocos2d.x.texture.pvrv2_has_alpha_premultiplied</key>
<false/>
<key>cocos2d.x.testcpp.autorun</key>
<false/>
<key>cocos2d.x.3d.max_dir_light_in_shader</key>
<integer>1</integer>
<key>cocos2d.x.3d.max_point_light_in_shader</key>
<integer>1</integer>
<key>cocos2d.x.3d.max_spot_light_in_shader</key>
<integer>1</integer>
<key>cocos2d.x.3d.animate_quality</key>
<integer>2</integer>
</dict>
<key>metadata</key>
<dict>
<key>format</key>
<integer>1</integer>
</dict>
</dict>
</plist>
文件开始两行为一些标注信息,不用于解析具体类容。节点形式分为以下几类:
<Node><Node1> ... </Node1></Node> 嵌套形式,一个节点中包含多个节点。
<Node>TEXT<Node> 单个节点形式,中间为该节点表示的值。TEXT 是一种特殊节点。
<Node ATT=VAL/> 单个节点或者多个节点都可带属性,ATT 表示该节点包含指定信息。
字典文件格式:
一般来说也是XML格式的文件,只是文件规定了一些规则用于该类型数据的解析,比如 onfig-example.plist 中一些 NODE 的名字属性:
dict 表示一个字典类型节点,该节点中的子节点将以 KEY-VALUE 的结构存在,在解析时必定遵循该规则。
VALUE 的 NODE 名则需要指定对应的数据类型,各种符合解析规则的数据类型。
DictMaker 继承抽象类 SAXDelegator 需要实现以下纯虚函数:
参数的意思:ctx SAXParser,name NODE,atts 指向属性的数组,KEY-VALUE 顺序直到 NULL
virtual void startElement(void *ctx, const char *name, const char **atts) = 0;
解析 NODE 头的回调。
virtual void endElement(void *ctx, const char *name) = 0;
解析 NODE 尾的回调。
virtual void textHandler(void *ctx, const char *s, int len) = 0;
解析 NODE 文本的回调。
DictMaker 的变量字段:
(很奇葩,全是公有的)
SAXResult _resultType;
表示根节点解析类型 SAX_RESULT_NONE 普通节点, SAX_RESULT_DICT 字典节点, SAX_RESULT_ARRAY 数组节点,数据解析前定义该数据的类型。
ValueMap _rootDict;
字典根节点
ValueVector _rootArray;
数组根节点
std::string _curKey;
当前的KEY
std::string _curValue;
当前的VALUE,字符串类型
SAXState _state;
当前节点存放VALUE的类型,SAX_NONE 空, SAX_KEY 键, SAX_DICT 字典, SAX_INT 整型, SAX_REAL 实数, SAX_STRING 字符串, SAX_ARRAY 数组
ValueMap* _curDict;
当前字典,每次构造字典数据时指向该字典的地址。
ValueVector* _curArray;
当前数组,每次构造数组数据时指向该数组的地址。
std::stack<ValueMap*> _dictStack;
用于保存字典节点的堆栈
std::stack<ValueVector*> _arrayStack;
用于保存数组节点的堆栈
std::stack<SAXState> _stateStack;
用于保存节点类型的地战
解析实例分析:文件 config-example.plist
CC_UNUSED_PARAM 无意义的宏定义,只是用于防止编译器检测到变量未使用警告。当一个节点开始时首先调用 startElement,
第一个节点为 plist,不是有效的定义类型,则设置 _state 为 SAX_NONE,这儿可以通过 atts 获取属性值。
plist 不是 TEXT 所以直接调用下一个节点的 startElement,
节点名为 ditct,表示这是一个符合字典定义结构的节点,构造字典节点时需要判断是否为数据节点的根节点,
void startElement(void *ctx, const char *name, const char **atts)
{
CC_UNUSED_PARAM(ctx);
CC_UNUSED_PARAM(atts);
const std::string sName(name);
if( sName == "dict" )
{
if(_resultType == SAX_RESULT_DICT && _rootDict.empty())
{//初始化根字典节点
_curDict = &_rootDict;
}
_state = SAX_DICT;
//获取上一个节点类型
SAXState preState = SAX_NONE;
if (! _stateStack.empty())
{
preState = _stateStack.top();
}
//判断父节点类型
if (SAX_ARRAY == preState)
{//若为数组则创建一个字典对象加入数组中,并赋值当前字典 _curDict
// add a new dictionary into the array
_curArray->push_back(Value(ValueMap()));
_curDict = &(_curArray->rbegin())->asValueMap();
}
else if (SAX_DICT == preState)
{//若为字典构造一个字典对象加入父字典中,并赋值当前字典 _curDict
// add a new dictionary into the pre dictionary
CCASSERT(! _dictStack.empty(), "The state is wrong!");
ValueMap* preDict = _dictStack.top();
(*preDict)[_curKey] = Value(ValueMap());
_curDict = &(*preDict)[_curKey].asValueMap();
}
//标记当前节点类型,并将当前字典 压入堆栈中
// record the dict state
_stateStack.push(_state);
_dictStack.push(_curDict);
}
else if(sName == "key")
{
_state = SAX_KEY;
}
else if(sName == "integer")
{
_state = SAX_INT;
}
else if(sName == "real")
{
_state = SAX_REAL;
}
else if(sName == "string")
{
_state = SAX_STRING;
}
else if (sName == "array")
{
//标记当前节点为数组
_state = SAX_ARRAY;
if (_resultType == SAX_RESULT_ARRAY && _rootArray.empty())
{//初始化根数组节点
_curArray = &_rootArray;
}
//判断父节点类型
SAXState preState = SAX_NONE;
if (! _stateStack.empty())
{
preState = _stateStack.top();
}
if (preState == SAX_DICT)
{//若为字典则在该节点下创建数组节点,并赋值当前数组 _curArray
(*_curDict)[_curKey] = Value(ValueVector());
_curArray = &(*_curDict)[_curKey].asValueVector();
}
else if (preState == SAX_ARRAY)
{//若为数组则在该节点下创建数组节点,并赋值当前数组 _curArray
CCASSERT(! _arrayStack.empty(), "The state is wrong!");
ValueVector* preArray = _arrayStack.top();
preArray->push_back(Value(ValueVector()));
_curArray = &(_curArray->rbegin())->asValueVector();
}
//标记当前节点类型,并将当前节点 压入堆栈中
// record the array state
_stateStack.push(_state);
_arrayStack.push(_curArray);
}
else
{
_state = SAX_NONE;
}
}
若为KEY则设置当前节点类型为 _state = SAX_KEY,下次将回调 textHandler,指定TEXT的字符串地址和长度,通过 _state 选择设置当前的值。
当前 KEY 内容读完后进入 endElement,根据当父节点类型、当前节点类型和当前值组织 DictMaker 的值。
若文件不以 DICT 为根节点,则会自动默认初始为 DICT,再保存数据。
初始化函数:
ValueMap dictionaryWithContentsOfFile(const std::string& fileName)通过字典文件初始化一个字典结构,_resultType = SAX_RESULT_DICT;
ValueMap dictionaryWithDataOfFile(const char* filedata, int filesize)
通过字典数据初始化一个字典结构,_resultType = SAX_RESULT_DICT;
ValueVector arrayWithContentsOfFile(const std::string& fileName)
通过数组文件初始化一个数组结构,_resultType = SAX_RESULT_ARRAY;
相关文章推荐
- Cocos2d-x 3.2 大富翁游戏项目开发-第七部分 获取角色路径_1
- cocos2dx内存管理
- cocos2dx 源码分析之 CCPoolManager
- Cocos2D-Android-1之源码详解:3.ActionsTest
- Cocos开发中性能优化工具介绍之Visual Studio内存泄漏检测工具Visual Leak Detector
- 【Cocos2d-x】之检测语言环境
- 解决Cocos2d点击电源键后游戏纹理失效
- 【Cocos2d-x】之编译so文件出错
- cocos2dx笔记之单例模式
- 【cocos2d-js系列问题】cocos2d-js创建帧动画的两种方法
- cocos2dx-3.x事件分发机制
- cocos2dx - 环境配置,项目创建
- Cocos2D-X shader(一) 渲染机制
- Cocos2D-Android-1之源码详解:2.ActionManagerTest
- COCOS2D-3.9 Data分析
- cocos2d(3)CCLayer的三个子类CCLayerColorCCLayerGridentCCLayerMultiplex
- COCOS2D-3.9 Value接口分析
- cocos2d (ZORDER、setTag、单点触屏)
- Cocos2D-Android-1之源码详解:1.Cocos2D
- cocos2d对动画的各种操作