这是很久以前写的笔记,很乱,找时间重新优化一下。
#ifndef _HALL_MSG_PARSER_H#define _HALL_MSG_PARSER_H#include "cocos2d.h"USING_NS_CC;using namespace std;/**isWhole �Ƿ���һ�����壬���Dz�ֳ�һ����һ��labelTTF��color ������ɫfontSize���ִ�Сfont ��������image��ǩ��url��/resourceĿ¼�¡�const char* str1 = "<sentences><characters isWhole=\"1\" color=\"00FFFF\" fontSize=\"28\" font=\"Microsoft YaHei\">[ϵͳ]</characters><characters isWhole=\"1\" color=\"FF00FF\" fontSize=\"28\" font=\"Microsoft YaHei\">����ţ��</characters><image>player_girl.png</image><characters isWhole=\"1\" color=\"FFFF00\" fontSize=\"28\" font=\"Microsoft YaHei\">�õ���</characters><characters isWhole=\"0\" color=\"CCAABB\" fontSize=\"28\" font=\"Microsoft YaHei\">��̽�ռұ��䡿x1</characters></sentences>";�÷���createһ��HallMsgParser��Ȼ��parseMsgFromXMLStrAndShow(const char*,CCSize)������һ��CClayer����Ϣ���������Layer�д����ң����ϵ�����䡣һ��HallMsgParserʵ������parser���char*��ÿ�η���һ���µ�CCLayer�����ַ���< С�ں� ʹ��<ʵ���滻 ������;��> ���ں� >& �� &�� ������(Ӣ��) '������\'" ˫���ţ�Ӣ�ģ� "������\"*/class HallMsgParser : public CCObject, public CCSAXDelegator{public:CREATE_FUNC(HallMsgParser);HallMsgParser();~HallMsgParser();bool init();bool reset();CCLayer* parseMsgFromXMLStrAndShow(const char* xml,CCSize size);void attachToLayer(CCLayer* layer,vector<CCNode*> contents);int utf8_char_len(char firstByte);/***��Ӧxml��ǩ��ʼ,�磺<string name="alex">, nameΪstring��attsΪstring�����ԣ���["name","alex"]*/virtual void startElement(void *ctx, const char *name, const char **atts);/***��Ӧxml��ǩ����,�磺</string>*/virtual void endElement(void *ctx, const char *name);/***��Ӧxml��ǩ�ı�,�磺<string name="alex">Alex Zhou</string>��Alex Zhou*/virtual void textHandler(void *ctx, const char *s, int len);private:bool parseWithString(const char* content);bool clearTmpData();private:vector<CCNode*> contents;ccColor3B color;string startXMLElement;string endXMLElement;//���ֵ�����string font;string tmp_txt;//���ֵ�����<characters isWhole="1",color="FFFFFF",fontSize="28",font="Microsoft YaHei"> [ϵͳ] </characters>//�����Ƿ�Ӧ��Ϊһ�����壬��һ��label��ʾ����[ϵͳ][С��ñ]:�����ţ��Ҳ����衣������е�[ϵͳ]��[С��ñ]��Ϊһ�����壬�������Ҳ����裬����һ����һ��label��int isWhole;//������ɫ//���ִ�Сint fontSize;char* m_key;//�������Ľڵ��Ƿ������֣�true�����֣�false��ͼƬbool isCharacter;};#endif
#include "comm\HallMsgParser.h"#include "IconvString.h"using namespace std;// 空格const static int SPACE = 32;// 换行const static int NEXTLINE = 10;// tab 横向制表符const static int TAB = 9;//默认的字体颜色rgb组成const static int R_BY_DEFAULT = 0xFF;const static int G_BY_DEFAULT = 0xFF;const static int B_BY_DEFAULT = 0xFF;//默认的字体大小const static int FONTSIZE_BY_DEFAULT = 18;//默认一条消息的消息框最大行数const static int LINE_MAX_BY_DEFAULT = 2;//消息默认的字间距const static float INTERVAL_X_BY_DEFAULT = 0;//消息的默认行间距const static float INTERVAL_Y_BY_DEFAULT = 0;//默认字体const static char FONT_BY_DEFAULT[] = "Microsoft YaHei";//文字节点,<characters ...>...</characters>const static char CHARACTERS_TAG[] = "characters";//图片节点.<image>...<image>const static char IMG_TAG[] = "image";const static char ATTR_IS_WHOLE_TAG[] = "isWhole";const static char ATTR_COLOR_TAG[] = "color";const static char ATTR_FONT_SIZE_TAG[] = "fontSize";const static char ATTR_FONT_TAG[] = "font";const unsigned char kFirstBitMask = 128; // 1000000const unsigned char kSecondBitMask = 64; // 0100000const unsigned char kThirdBitMask = 32; // 0010000const unsigned char kFourthBitMask = 16; // 0001000const unsigned char kFifthBitMask = 8; // 0000100const static std::string EMPTY_STR = "";//默认字体颜色const static ccColor3B FONT_COLOR_BY_DEFAULT = ccWHITE;HallMsgParser::HallMsgParser(){}HallMsgParser::~HallMsgParser(){CCLog("**********~HallMsgParser**********");reset();CCLog("**********reset()**********");}//只取了size中的width。CCLayer* HallMsgParser::parseMsgFromXMLStrAndShow(const char* xml,CCSize size){bool isSuccess = false;if(!xml||size.width == 0){CCLog(" xml string is null or mayby the width of CCSize is 0");return NULL;}CCLayer* tmpLayer = CCLayer::create();do{CC_BREAK_IF(NULL == tmpLayer);tmpLayer->setContentSize(size);CCLog("***********ready to parse string works*************");CC_BREAK_IF(!(isSuccess = parseWithString(xml)));CCLog("*********** parse string successfully *************");//解析成功,把解析出的数据填充到layer中。attachToLayer(tmpLayer,contents);}while(0);if(!isSuccess){CCLog("***************parse string failed*************");}reset();return tmpLayer;}void HallMsgParser::attachToLayer(CCLayer* layer,vector<CCNode*> contents){CCLog("**********attachToLayer**********");if(layer == NULL||contents.size() == 0){CCLOG("*****attach to layer failed!*****");return;}//文字的高度取决于最高的那个CCNode。float height_max = -1;//图层的位置CCPoint layerPos = layer->getPosition();//图层高度,宽度float layer_height = layer->getContentSize().height;float layer_width = layer->getContentSize().width;//图层最左边x坐标float left_max = layerPos.x - (layer_width/2);//图层最顶端y坐标float top_max = layerPos.y + (layer_height/2);CCLog("********** content size is ::%d",contents.size());for (unsigned int i = 0;i<contents.size(); i++){float tmp = contents[i]->getContentSize().height;height_max = height_max < tmp ? tmp : height_max;}CCLog("********** highest item of contents is :: %f",height_max);//当前已经填充到第几行了。int curLineTmp = 1;//在当前行已经占用了多宽的空间。int currWidthTmp = 0;float unit_height = 0;float unit_width = 0;float unitPosX = 0;float unitPosY = 0;for (unsigned int i = 0; i<contents.size(); i++){CCLog("********** current line is %d **********",curLineTmp);unit_height = contents[i]->getContentSize().height;unit_width = contents[i]->getContentSize().width;//是否可以在当前行填充当前子label,否则应该另起一行if(currWidthTmp + unit_width > layer_width && unit_width <= layer_width){if(curLineTmp == LINE_MAX_BY_DEFAULT){break;}//填充行+1curLineTmp++;//另起一行,当前填充的空间需要清0currWidthTmp = 0;}//一个labelttf的宽度都超过了屏幕宽度,干脆不要显示了,丢弃。if(unit_width > layer_width){CCLog("********** the width of current unit is larger than layer_width,won't dispear. unitWidth:%f**********",unit_width);continue;}unitPosX = left_max + currWidthTmp + unit_width/2 + INTERVAL_X_BY_DEFAULT;unitPosY = top_max - (height_max + INTERVAL_Y_BY_DEFAULT) * (curLineTmp - 1) - unit_height/2 - INTERVAL_Y_BY_DEFAULT;CCLog("********** position of unit %d: %f,%f**********",i,unitPosX,unitPosY);contents[i]->setPosition(CCPointMake(unitPosX,unitPosY));currWidthTmp += unit_width;layer->addChild(contents[i]);}//重新设置消息框宽高,layer->setContentSize(CCSize(layer_width,curLineTmp * height_max));}bool HallMsgParser::parseWithString(const char *content){bool isSuccess = false;if(!content){CCLog("********NULL content*******");return isSuccess;}CCSAXParser _parse;_parse.setDelegator(this);#if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)//gbk转utf-8size_t inLen = strlen(content);size_t outLen = (inLen << 1);//转到utf-8存储,字节数放大2倍。//记得freechar *outBuf = (char *)malloc(outLen);//把传入的xml一律转换成utf-8gbk2utf8((char *)content, inLen, outBuf, outLen);isSuccess = _parse.parse(outBuf, strlen(outBuf));free(outBuf);#elseisSuccess = _parse.parse(content, strlen(content));#endifreturn isSuccess;}bool HallMsgParser::reset(){clearTmpData();contents.clear();return true;}bool HallMsgParser::clearTmpData(){//解析前先初始化一些相关数据m_key = NULL;startXMLElement = EMPTY_STR;endXMLElement = EMPTY_STR;//默认把解析到的节点看成是文字节点isCharacter = true;//默认解析到的节点的内容是整体的。因为有种情况是:必须把解析到的一串文字一个文字一个label这样拆分。isWhole = true;//默认的字体颜色color = FONT_COLOR_BY_DEFAULT;font = FONT_BY_DEFAULT;fontSize = FONTSIZE_BY_DEFAULT;tmp_txt = EMPTY_STR;//contents.clear();return true;}bool HallMsgParser::init(){return reset();}void HallMsgParser::startElement(void *ctx, const char *name, const char **atts){startXMLElement = (char *)name;CCLog("********** start= %s **********", startXMLElement.c_str());//节点名称m_key = (char *)name;//文字if(0 == strcmp(CHARACTERS_TAG,m_key)){//遍历这个文字节点,获取所有相关属性while(atts && *atts){//节点属性名称const char* attrKey = *atts;//右移一个单位,指向属性值++atts;//属性值const char* attrValue = *atts;//CCLog("***********%s::%s****************",attrKey,attrValue);if(attrValue && *attrValue){if(0 == strcmp(ATTR_IS_WHOLE_TAG,attrKey)){isWhole = atoi(attrValue);CCLog("*******isWhole::%d*******",isWhole);}else if(0 == strcmp(ATTR_COLOR_TAG,attrKey)){if(strlen(attrValue) == 6){//tmp = "00FFFF",接续00,ff,ffconst string tmp = attrValue;int r = R_BY_DEFAULT;int g = G_BY_DEFAULT;int b = B_BY_DEFAULT;sscanf((tmp.substr(0,2)).c_str(),"%x",&r);sscanf((tmp.substr(2,2)).c_str(),"%x",&g);sscanf((tmp.substr(4,2)).c_str(),"%x",&b);color = ccc3(r,g,b);CCLog("*****r::%c,g::%c,b::%c*******",color.r,color.g,color.b);}}else if(0 == strcmp(ATTR_FONT_SIZE_TAG,attrKey)){fontSize = atoi(attrValue);CCLog("*******fontSize::%d*******",fontSize);}else if(0 == strcmp(ATTR_FONT_TAG,attrKey)){font = attrValue;CCLog("*******font::%s*******",font.c_str());}}//CCLOG("*****%s::%s*****",startXMLElement,attrKey);atts++;}//防止值异常isWhole==1||isWhole==0?0:isWhole=1;fontSize>0?0:fontSize=18;isCharacter = true;}//解析到的节点是图片else if(0 == strcmp(IMG_TAG,m_key)){isCharacter = false;}CCLog("*******isCharacter::%d*******",isCharacter);}void HallMsgParser::endElement(void *ctx, const char *name){endXMLElement = (char *)name;CCLog("********** end= %s **********", endXMLElement.c_str());if(isWhole ==1 && 0 != strcmp(tmp_txt.c_str(),EMPTY_STR.c_str())){do{CCLog("*****content:%s,*****fontName:%s,*****fontSize:%d,*****",tmp_txt.c_str(),font.c_str(),fontSize);CCLabelTTF* unit = CCLabelTTF::create(tmp_txt.c_str(),font.c_str(),fontSize);CC_BREAK_IF(NULL == unit);unit->setColor(color);contents.push_back(unit);}while(0);}clearTmpData();//还原所有值到默认值}void HallMsgParser::textHandler(void *ctx, const char *s, int len){CCLog("****************txtHandle***************");//文字内容,或者image的urlstring value((char *)s, 0, len);string tmp(EMPTY_STR);//是否全是非正常字符bool noValue = true;for(int i = 0; i < len; ++i){if(s[i] != SPACE && s[i] != NEXTLINE && s[i] != TAB){noValue = false;break;}}if(noValue) return;//文字if(isCharacter){//所有文字在一个label中if(isWhole == 1){tmp_txt += value;CCLog("****** tmp_txt:: %s********",tmp_txt.c_str());}//一个文字一个labelelse{for (unsigned int i = 0; i < value.length(); i++){//utf-8编码,根据首字节,判断这个字符所占字节数int offset = utf8_char_len(value[i]);tmp = value.substr(i,offset);i += (offset-1);CCLog("*****content:%s,*****fontName:%s,fontSize:%d*****",tmp.c_str(),font.c_str(),fontSize);CCLabelTTF* unit = CCLabelTTF::create(tmp.c_str(),font.c_str(),fontSize);unit->setColor(color);contents.push_back(unit);tmp = EMPTY_STR;}}}//图片else{do{CCLog("*****image url: %s*****",value.c_str());CCSprite* image = CCSprite::create(value.c_str());CC_BREAK_IF(NULL == image);contents.push_back(image);}while(0);}}int HallMsgParser::utf8_char_len(char firstByte){string::difference_type offset = 1;if(firstByte & kFirstBitMask) // This means the first byte has a value greater than 127, and so is beyond the ASCII range.{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.{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.offset = 4;elseoffset = 3;}else{offset = 2;}}return offset;}
继承自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
6**
1 startelement
2 startelement
3 textHandler
4 endElement
5 textHandler,在解析完后,还会执行一次这个函数。
6 endElement
