这是很久以前写的笔记,很乱,找时间重新优化一下。

    1. #ifndef _HALL_MSG_PARSER_H
    2. #define _HALL_MSG_PARSER_H
    3. #include "cocos2d.h"
    4. USING_NS_CC;
    5. using namespace std;
    6. /**
    7. isWhole �Ƿ���һ�����壬���Dz�ֳ�һ����һ��labelTTF��
    8. color ������ɫ
    9. fontSize���ִ�С
    10. font ��������
    11. image��ǩ��url��/resourceĿ¼�¡�
    12. const char* str1 = "<sentences><characters isWhole=\"1\" color=\"00FFFF\" fontSize=\"28\" font=\"Microsoft YaHei\">[ϵͳ]</characters>
    13. <characters isWhole=\"1\" color=\"FF00FF\" fontSize=\"28\" font=\"Microsoft YaHei\">����ţ��</characters>
    14. <image>player_girl.png</image>
    15. <characters isWhole=\"1\" color=\"FFFF00\" fontSize=\"28\" font=\"Microsoft YaHei\">�õ���</characters>
    16. <characters isWhole=\"0\" color=\"CCAABB\" fontSize=\"28\" font=\"Microsoft YaHei\">��̽�ռұ��䡿x1</characters>
    17. </sentences>";
    18. �÷���createһ��HallMsgParser��Ȼ��parseMsgFromXMLStrAndShow(const char*,CCSize)������һ��CClayer����Ϣ���������Layer�д����ң����ϵ�����䡣
    19. һ��HallMsgParserʵ������parser���char*��ÿ�η���һ���µ�CCLayer
    20. �����ַ���
    21. < С�ں� ʹ��&lt;ʵ���滻 ������;��
    22. > ���ں� &gt;
    23. & �� &amp;
    24. �� ������(Ӣ��) &apos;������\'
    25. " ˫���ţ�Ӣ�ģ� &quot;������\"
    26. */
    27. class HallMsgParser : public CCObject, public CCSAXDelegator
    28. {
    29. public:
    30. CREATE_FUNC(HallMsgParser);
    31. HallMsgParser();
    32. ~HallMsgParser();
    33. bool init();
    34. bool reset();
    35. CCLayer* parseMsgFromXMLStrAndShow(const char* xml,CCSize size);
    36. void attachToLayer(CCLayer* layer,vector<CCNode*> contents);
    37. int utf8_char_len(char firstByte);
    38. /**
    39. *��Ӧxml��ǩ��ʼ,�磺<string name="alex">, nameΪstring��attsΪstring�����ԣ���["name","alex"]
    40. */
    41. virtual void startElement(void *ctx, const char *name, const char **atts);
    42. /**
    43. *��Ӧxml��ǩ����,�磺</string>
    44. */
    45. virtual void endElement(void *ctx, const char *name);
    46. /**
    47. *��Ӧxml��ǩ�ı�,�磺<string name="alex">Alex Zhou</string>��Alex Zhou
    48. */
    49. virtual void textHandler(void *ctx, const char *s, int len);
    50. private:
    51. bool parseWithString(const char* content);
    52. bool clearTmpData();
    53. private:
    54. vector<CCNode*> contents;
    55. ccColor3B color;
    56. string startXMLElement;
    57. string endXMLElement;
    58. //���ֵ�����
    59. string font;
    60. string tmp_txt;
    61. //���ֵ�����<characters isWhole="1",color="FFFFFF",fontSize="28",font="Microsoft YaHei"> [ϵͳ] </characters>
    62. //�����Ƿ�Ӧ��Ϊһ�����壬��һ��label��ʾ����[ϵͳ][С��ñ]:�����ţ��Ҳ����衣������е�[ϵͳ]��[С��ñ]��Ϊһ�����壬�������Ҳ����裬����һ����һ��label��
    63. int isWhole;
    64. //������ɫ
    65. //���ִ�С
    66. int fontSize;
    67. char* m_key;
    68. //�������Ľڵ��Ƿ������֣�true�����֣�false��ͼƬ
    69. bool isCharacter;
    70. };
    71. #endif
    1. #include "comm\HallMsgParser.h"
    2. #include "IconvString.h"
    3. using namespace std;
    4. // 空格
    5. const static int SPACE = 32;
    6. // 换行
    7. const static int NEXTLINE = 10;
    8. // tab 横向制表符
    9. const static int TAB = 9;
    10. //默认的字体颜色rgb组成
    11. const static int R_BY_DEFAULT = 0xFF;
    12. const static int G_BY_DEFAULT = 0xFF;
    13. const static int B_BY_DEFAULT = 0xFF;
    14. //默认的字体大小
    15. const static int FONTSIZE_BY_DEFAULT = 18;
    16. //默认一条消息的消息框最大行数
    17. const static int LINE_MAX_BY_DEFAULT = 2;
    18. //消息默认的字间距
    19. const static float INTERVAL_X_BY_DEFAULT = 0;
    20. //消息的默认行间距
    21. const static float INTERVAL_Y_BY_DEFAULT = 0;
    22. //默认字体
    23. const static char FONT_BY_DEFAULT[] = "Microsoft YaHei";
    24. //文字节点,<characters ...>...</characters>
    25. const static char CHARACTERS_TAG[] = "characters";
    26. //图片节点.<image>...<image>
    27. const static char IMG_TAG[] = "image";
    28. const static char ATTR_IS_WHOLE_TAG[] = "isWhole";
    29. const static char ATTR_COLOR_TAG[] = "color";
    30. const static char ATTR_FONT_SIZE_TAG[] = "fontSize";
    31. const static char ATTR_FONT_TAG[] = "font";
    32. const unsigned char kFirstBitMask = 128; // 1000000
    33. const unsigned char kSecondBitMask = 64; // 0100000
    34. const unsigned char kThirdBitMask = 32; // 0010000
    35. const unsigned char kFourthBitMask = 16; // 0001000
    36. const unsigned char kFifthBitMask = 8; // 0000100
    37. const static std::string EMPTY_STR = "";
    38. //默认字体颜色
    39. const static ccColor3B FONT_COLOR_BY_DEFAULT = ccWHITE;
    40. HallMsgParser::HallMsgParser()
    41. {
    42. }
    43. HallMsgParser::~HallMsgParser()
    44. {
    45. CCLog("**********~HallMsgParser**********");
    46. reset();
    47. CCLog("**********reset()**********");
    48. }
    49. //只取了size中的width。
    50. CCLayer* HallMsgParser::parseMsgFromXMLStrAndShow(const char* xml,CCSize size)
    51. {
    52. bool isSuccess = false;
    53. if(!xml||size.width == 0)
    54. {
    55. CCLog(" xml string is null or mayby the width of CCSize is 0");
    56. return NULL;
    57. }
    58. CCLayer* tmpLayer = CCLayer::create();
    59. do
    60. {
    61. CC_BREAK_IF(NULL == tmpLayer);
    62. tmpLayer->setContentSize(size);
    63. CCLog("***********ready to parse string works*************");
    64. CC_BREAK_IF(!(isSuccess = parseWithString(xml)));
    65. CCLog("*********** parse string successfully *************");
    66. //解析成功,把解析出的数据填充到layer中。
    67. attachToLayer(tmpLayer,contents);
    68. }
    69. while(0);
    70. if(!isSuccess)
    71. {
    72. CCLog("***************parse string failed*************");
    73. }
    74. reset();
    75. return tmpLayer;
    76. }
    77. void HallMsgParser::attachToLayer(CCLayer* layer,vector<CCNode*> contents)
    78. {
    79. CCLog("**********attachToLayer**********");
    80. if(layer == NULL||contents.size() == 0)
    81. {
    82. CCLOG("*****attach to layer failed!*****");
    83. return;
    84. }
    85. //文字的高度取决于最高的那个CCNode。
    86. float height_max = -1;
    87. //图层的位置
    88. CCPoint layerPos = layer->getPosition();
    89. //图层高度,宽度
    90. float layer_height = layer->getContentSize().height;
    91. float layer_width = layer->getContentSize().width;
    92. //图层最左边x坐标
    93. float left_max = layerPos.x - (layer_width/2);
    94. //图层最顶端y坐标
    95. float top_max = layerPos.y + (layer_height/2);
    96. CCLog("********** content size is ::%d",contents.size());
    97. for (unsigned int i = 0;i<contents.size(); i++)
    98. {
    99. float tmp = contents[i]->getContentSize().height;
    100. height_max = height_max < tmp ? tmp : height_max;
    101. }
    102. CCLog("********** highest item of contents is :: %f",height_max);
    103. //当前已经填充到第几行了。
    104. int curLineTmp = 1;
    105. //在当前行已经占用了多宽的空间。
    106. int currWidthTmp = 0;
    107. float unit_height = 0;
    108. float unit_width = 0;
    109. float unitPosX = 0;
    110. float unitPosY = 0;
    111. for (unsigned int i = 0; i<contents.size(); i++)
    112. {
    113. CCLog("********** current line is %d **********",curLineTmp);
    114. unit_height = contents[i]->getContentSize().height;
    115. unit_width = contents[i]->getContentSize().width;
    116. //是否可以在当前行填充当前子label,否则应该另起一行
    117. if(currWidthTmp + unit_width > layer_width && unit_width <= layer_width)
    118. {
    119. if(curLineTmp == LINE_MAX_BY_DEFAULT)
    120. {
    121. break;
    122. }
    123. //填充行+1
    124. curLineTmp++;
    125. //另起一行,当前填充的空间需要清0
    126. currWidthTmp = 0;
    127. }
    128. //一个labelttf的宽度都超过了屏幕宽度,干脆不要显示了,丢弃。
    129. if(unit_width > layer_width)
    130. {
    131. CCLog("********** the width of current unit is larger than layer_width,won't dispear. unitWidth:%f**********",unit_width);
    132. continue;
    133. }
    134. unitPosX = left_max + currWidthTmp + unit_width/2 + INTERVAL_X_BY_DEFAULT;
    135. unitPosY = top_max - (height_max + INTERVAL_Y_BY_DEFAULT) * (curLineTmp - 1) - unit_height/2 - INTERVAL_Y_BY_DEFAULT;
    136. CCLog("********** position of unit %d: %f,%f**********",i,unitPosX,unitPosY);
    137. contents[i]->setPosition(CCPointMake(unitPosX,unitPosY));
    138. currWidthTmp += unit_width;
    139. layer->addChild(contents[i]);
    140. }
    141. //重新设置消息框宽高,
    142. layer->setContentSize(CCSize(layer_width,curLineTmp * height_max));
    143. }
    144. bool HallMsgParser::parseWithString(const char *content)
    145. {
    146. bool isSuccess = false;
    147. if(!content)
    148. {
    149. CCLog("********NULL content*******");
    150. return isSuccess;
    151. }
    152. CCSAXParser _parse;
    153. _parse.setDelegator(this);
    154. #if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
    155. //gbk转utf-8
    156. size_t inLen = strlen(content);
    157. size_t outLen = (inLen << 1);//转到utf-8存储,字节数放大2倍。
    158. //记得free
    159. char *outBuf = (char *)malloc(outLen);
    160. //把传入的xml一律转换成utf-8
    161. gbk2utf8((char *)content, inLen, outBuf, outLen);
    162. isSuccess = _parse.parse(outBuf, strlen(outBuf));
    163. free(outBuf);
    164. #else
    165. isSuccess = _parse.parse(content, strlen(content));
    166. #endif
    167. return isSuccess;
    168. }
    169. bool HallMsgParser::reset()
    170. {
    171. clearTmpData();
    172. contents.clear();
    173. return true;
    174. }
    175. bool HallMsgParser::clearTmpData()
    176. {
    177. //解析前先初始化一些相关数据
    178. m_key = NULL;
    179. startXMLElement = EMPTY_STR;
    180. endXMLElement = EMPTY_STR;
    181. //默认把解析到的节点看成是文字节点
    182. isCharacter = true;
    183. //默认解析到的节点的内容是整体的。因为有种情况是:必须把解析到的一串文字一个文字一个label这样拆分。
    184. isWhole = true;
    185. //默认的字体颜色
    186. color = FONT_COLOR_BY_DEFAULT;
    187. font = FONT_BY_DEFAULT;
    188. fontSize = FONTSIZE_BY_DEFAULT;
    189. tmp_txt = EMPTY_STR;
    190. //contents.clear();
    191. return true;
    192. }
    193. bool HallMsgParser::init()
    194. {
    195. return reset();
    196. }
    197. void HallMsgParser::startElement(void *ctx, const char *name, const char **atts)
    198. {
    199. startXMLElement = (char *)name;
    200. CCLog("********** start= %s **********", startXMLElement.c_str());
    201. //节点名称
    202. m_key = (char *)name;
    203. //文字
    204. if(0 == strcmp(CHARACTERS_TAG,m_key))
    205. {
    206. //遍历这个文字节点,获取所有相关属性
    207. while(atts && *atts)
    208. {
    209. //节点属性名称
    210. const char* attrKey = *atts;
    211. //右移一个单位,指向属性值
    212. ++atts;
    213. //属性值
    214. const char* attrValue = *atts;
    215. //CCLog("***********%s::%s****************",attrKey,attrValue);
    216. if(attrValue && *attrValue)
    217. {
    218. if(0 == strcmp(ATTR_IS_WHOLE_TAG,attrKey))
    219. {
    220. isWhole = atoi(attrValue);
    221. CCLog("*******isWhole::%d*******",isWhole);
    222. }
    223. else if(0 == strcmp(ATTR_COLOR_TAG,attrKey))
    224. {
    225. if(strlen(attrValue) == 6)
    226. {
    227. //tmp = "00FFFF",接续00,ff,ff
    228. const string tmp = attrValue;
    229. int r = R_BY_DEFAULT;
    230. int g = G_BY_DEFAULT;
    231. int b = B_BY_DEFAULT;
    232. sscanf((tmp.substr(0,2)).c_str(),"%x",&r);
    233. sscanf((tmp.substr(2,2)).c_str(),"%x",&g);
    234. sscanf((tmp.substr(4,2)).c_str(),"%x",&b);
    235. color = ccc3(r,g,b);
    236. CCLog("*****r::%c,g::%c,b::%c*******",color.r,color.g,color.b);
    237. }
    238. }
    239. else if(0 == strcmp(ATTR_FONT_SIZE_TAG,attrKey))
    240. {
    241. fontSize = atoi(attrValue);
    242. CCLog("*******fontSize::%d*******",fontSize);
    243. }
    244. else if(0 == strcmp(ATTR_FONT_TAG,attrKey))
    245. {
    246. font = attrValue;
    247. CCLog("*******font::%s*******",font.c_str());
    248. }
    249. }
    250. //CCLOG("*****%s::%s*****",startXMLElement,attrKey);
    251. atts++;
    252. }
    253. //防止值异常
    254. isWhole==1||isWhole==0?0:isWhole=1;
    255. fontSize>0?0:fontSize=18;
    256. isCharacter = true;
    257. }
    258. //解析到的节点是图片
    259. else if(0 == strcmp(IMG_TAG,m_key))
    260. {
    261. isCharacter = false;
    262. }
    263. CCLog("*******isCharacter::%d*******",isCharacter);
    264. }
    265. void HallMsgParser::endElement(void *ctx, const char *name)
    266. {
    267. endXMLElement = (char *)name;
    268. CCLog("********** end= %s **********", endXMLElement.c_str());
    269. if(isWhole ==1 && 0 != strcmp(tmp_txt.c_str(),EMPTY_STR.c_str()))
    270. {
    271. do
    272. {
    273. CCLog("*****content:%s,*****fontName:%s,*****fontSize:%d,*****",tmp_txt.c_str(),font.c_str(),fontSize);
    274. CCLabelTTF* unit = CCLabelTTF::create(tmp_txt.c_str(),font.c_str(),fontSize);
    275. CC_BREAK_IF(NULL == unit);
    276. unit->setColor(color);
    277. contents.push_back(unit);
    278. }while(0);
    279. }
    280. clearTmpData();
    281. //还原所有值到默认值
    282. }
    283. void HallMsgParser::textHandler(void *ctx, const char *s, int len)
    284. {
    285. CCLog("****************txtHandle***************");
    286. //文字内容,或者image的url
    287. string value((char *)s, 0, len);
    288. string tmp(EMPTY_STR);
    289. //是否全是非正常字符
    290. bool noValue = true;
    291. for(int i = 0; i < len; ++i)
    292. {
    293. if(s[i] != SPACE && s[i] != NEXTLINE && s[i] != TAB)
    294. {
    295. noValue = false;
    296. break;
    297. }
    298. }
    299. if(noValue) return;
    300. //文字
    301. if(isCharacter)
    302. {
    303. //所有文字在一个label中
    304. if(isWhole == 1)
    305. {
    306. tmp_txt += value;
    307. CCLog("****** tmp_txt:: %s********",tmp_txt.c_str());
    308. }
    309. //一个文字一个label
    310. else
    311. {
    312. for (unsigned int i = 0; i < value.length(); i++)
    313. {
    314. //utf-8编码,根据首字节,判断这个字符所占字节数
    315. int offset = utf8_char_len(value[i]);
    316. tmp = value.substr(i,offset);
    317. i += (offset-1);
    318. CCLog("*****content:%s,*****fontName:%s,fontSize:%d*****",tmp.c_str(),font.c_str(),fontSize);
    319. CCLabelTTF* unit = CCLabelTTF::create(tmp.c_str(),font.c_str(),fontSize);
    320. unit->setColor(color);
    321. contents.push_back(unit);
    322. tmp = EMPTY_STR;
    323. }
    324. }
    325. }
    326. //图片
    327. else
    328. {
    329. do
    330. {
    331. CCLog("*****image url: %s*****",value.c_str());
    332. CCSprite* image = CCSprite::create(value.c_str());
    333. CC_BREAK_IF(NULL == image);
    334. contents.push_back(image);
    335. }while(0);
    336. }
    337. }
    338. int HallMsgParser::utf8_char_len(char firstByte)
    339. {
    340. string::difference_type offset = 1;
    341. if(firstByte & kFirstBitMask) // This means the first byte has a value greater than 127, and so is beyond the ASCII range.
    342. {
    343. if(firstByte & kThirdBitMask) // This means that the first byte has a value greater than 224, and so it must be at least a three-octet code point.
    344. {
    345. if(firstByte & kFourthBitMask) // This means that the first byte has a value greater than 240, and so it must be a four-octet code point.
    346. offset = 4;
    347. else
    348. offset = 3;
    349. }
    350. else
    351. {
    352. offset = 2;
    353. }
    354. }
    355. return offset;
    356. }

    继承自CCSAXDelegator,实现startElement(),endElement(),和textHandler()三个函数。解析出的结果存入CCdictionary中,一键值对存储。相当于一个map。
    核心:三个过程。
    virtual void startElement(void ctx, const char name, const char atts) = 0;
    这是解析到一个以开头的标签。这里应该把标签名保存。

    virtual void endElement(void ctx, const char name) = 0;
    这是解析到一个以
    的标签,

    virtual void textHandler(void ctx, const char s, int len) = 0;
    这是解析之间的值。

    注意:解析过程是:
    1
    23100045
    6**
    1 startelement
    2 startelement
    3 textHandler
    4 endElement
    5 textHandler,在解析完后,还会执行一次这个函数。

    6 endElement