Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Регистрация Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Котяра

Оценить эту запись

Утилитный класс парсинга xml (AS2)

Запись от Котяра размещена 04.12.2009 в 11:36
Обновил(-а) Котяра 25.02.2010 в 09:53

Как - то (вчера), мне надоели жутко разветвлённые конструкции switch/ case при парсинге xml ( в чужом коде). Так как мне необходимо было переписать парсер, то я решил избавится от этих надоедливых конструкций
было:

Код AS1/AS2:
while(xmlPos != null) {
		xmlName = xmlPos.nodeName.toLowerCase();
		xmlAttr = xmlPos.attributes;
		if(xmlName != null) {
			//Output("<"+xmlName+"> was found...");
			// нашли реальный узел
			switch(xmlName) {
 
				case "server" :
					switch(xmlAttr["command"]) {
						case "start" :
						case "bet" :
						case "chance" :							
						case "bonus" :
						case "pong" :
						case "miniprize_games" :
						case "swim_scatters" :
							delete gameResult;
							gameResult = new Object();
							gameResult["status"] = xmlAttr["status"];
							//Output("\t\t server command = " + xmlAttr["command"] + " found.");
 
							/* 20091024: при получении статуса EXIT или EXCESS */
							if (gameResult["status"] == "exit" || gameResult["status"] == "excess") {
								mInterface.sendDefaultDebugInfo();												// шлем дефолтное сообщение с логом
								mInterface.mButtonExit.DoRelease();												// выходим в лобби
								this._parent.mCommon.mWins.mWinMsg.Show({text:GetText("text_error_sorry")}); 	// показываем окно с извинениями								
							}
							/* --- */
 
						break;
 
						case "match" :							
							if(xmlAttr["status"]=="ok") {
								if(mTestNoMatch.vis)   mTestNoMatch.Hide();
 
								// если начался новый турнир
								if(mMatch.IsOver)  {
									mMatch.IsOver = false;
									mMatch.Timeout = false;
									//mGame.SetupInterface("gamewait2");
								}
							}
						break;
 
						case '':
						case undefined :
								if(xmlAttr["status"].split('_').shift()=="match") {
									if(!mMatch)  mMatch = {};
									if(!mMatch.stack)  mMatch.stack = {};
									mMatch.stack[xmlAttr["status"]] = 1;
								}
						break;
 
						default : 
							mTestNoMatch.Show();
					}
				break;
 
 
				case "reel" :
					if (Vars.multiTapeReel != 1) {
						HC.ReelsLen["reel_"+xmlAttr["id"]] = int(xmlAttr["length"]);
						mReels.ReelsLen["reel_"+xmlAttr["id"]] = int(xmlAttr["length"]);
						mReels.ReelsLayout["reel_"+xmlAttr["id"]] = xmlAttr["layout"];
					}
				break;
 
				case "reels":
				case "reels2":
				case "reels3":
					mReels.api.reelsLayoutAdd ({ xml_name:xmlName, xml_data:xmlPos });					
					//reel_set
				break;				
 
				case "shift" :
					gameResult["server_shift"] = xmlAttr["server"];
					gameResult["user_shift"] = xmlAttr["user"]
 
					if(start_shift == undefined) var start_shift = gameResult["server_shift"];
 
					for(i = 1 ; i <= xmlAttr["server"].split(",").length;  i++){
						gameResult["reel_"+i] = xmlAttr["server"].split(",")[i-1];
					}
				break;
			...итп итд
стало:
Код AS1/AS2:
        /**
	 * Вложенные блоки в основной xml
	 * @param	xml
	 */
	private function parseServerNodes(xml:XMLNode):Void
	{
		trace("SlotParser.parseServerNodes > xml : " + xml);
 
		TagParser.add([ServerTag.SLOT, ServerTag.SLOTS], parseSlots,this);
		TagParser.add(ServerTag.SHIFT, 	parseShift,this);
		TagParser.add(ServerTag.PLAYER,	parsePlayer,this);
		// парсим с очисткой стека парсеров
		TagParser.parse(xml,true);
          }
 
	/**
	 * Обработчик блока slot
	 * @param	xml
	 */
	private function parseSlots(xml:XMLNode):Void
	{
		trace("SlotParser.parseSlots > xml : " + xml);
		TagParser.add(SlotsTag.COMBINATIONS, parseCombinations, this);
		//TagParser.add(SlotsTag.REEL, parseReel, this);
		TagParser.add([SlotsTag.REELS, SlotsTag.REELS2,SlotsTag.REELS3], parseReels, this);
		TagParser.add(SlotsTag.PAYLINES, parsePaylines, this);
		TagParser.add(SlotsTag.SYMBOLS, parseSymbol, this);	
		TagParser.parse(xml);
	}
кроме этого добавил кучу классов строковых констант для парсинга xml (имена аттрибутов и нодов)
код в общем количестве строк и файлов (был вообще в одном инклуд файле на 5000 строк) может и станет длинее, но понятнее 100 пудово!

Вот собственно и сам класс парсинга:

Код AS1/AS2:
/**
 * Утилитный класс парсинга XML.
 * !ВНИМАНИЕ! Ипользуются глобальные статичные методы.
 * @author k0t0vich
 */
class ru.globo.utils.TagParser
{
	static private  var _functionListsArray:Array=[{}];
	//static private  var _currentParsersList:Object = {};
	static private var _instance:TagParser;
	static private var listCounter:Number = 0;
 
	static public function get _currentParsersList():Object 
	{ 
		if (_functionListsArray[listCounter] == undefined) _functionListsArray[listCounter] = {};
		return _functionListsArray[listCounter];
	}
 
	/**
	 * Добавить ф-цию - xml парсер 	по имени нода (массиву имён).
	 * Добавляется в текущий список.
	 * @param	tags			строка или массив строк
	 * @param	parseFunction	ф-ция вида func(xmlNode:XMLNode)
	 * @param	scope			объект для вызова ф-ции
	 */
	static public function add(tags, parseFunction:Function,scope:Object)
	{
 
		if (typeof(tags) == "object") 
		{
			for (var name:String in tags) 
			{
				var tag = tags[name];
				if (typeof(tag) == "string") 
					addOne(tag, parseFunction, scope);
			}
 
		}
		else if (typeof(tags) == "string") 
		{
			addOne(tags, parseFunction, scope);
		}	
	}
 
 
	/**
	 * Добавить парсер по строке
	 * @param	tag					строго строка
	 * @param	parseFunction		ф-ция вида func(xmlNode:XMLNode)
	 * @param	scope				объект для вызова ф-ции
	 */
	static private function addOne(tag:String, parseFunction:Function, scope:Object)
	{
		//trace("TagParser.addOne > tag : " + tag + ", parseFunction : " + parseFunction + ", scope : " + scope+" listCounter=" + listCounter);
		_currentParsersList[tag] = {func:parseFunction,scope:scope};
	}
 
	/**
	 * Очистить список парсеров
	 */
	static public function clear():Void
	{
		//trace("TagParser.clear");
		_functionListsArray = [ { } ];
		listCounter = 0;
	}
 
	/**
	 * Распарсить xml по имени нода.
	 * Вызов этой ф-ции прекращает ввод парсеров для этой xml, при следующем add - парсеры добавятся в другой список.
	 * @param	xml						xmlNode для парсинга
	 * @param	clearAfterParse			флаг очистки списков. для xml - являющейся корневой - необходимо передавать true
	 */ 
	static public function parse(xml:XMLNode, clearAfterParse:Boolean)
	{
		// запоминаем счётчик - индекс, чтоб использовать список парсеров для данного блока в случае вложенных парсеров
		var counter:Number = listCounter;
		listCounter++;
		var len:Number = xml.childNodes.length;
		for (var i:Number = 0; i < len; i++) 
		{
				var xmlNode =  xml.childNodes[i];	
				var xmlName:String = xmlNode.nodeName.toLowerCase();
				var item = _functionListsArray[counter][xmlName];
				// если есть соответствия то вызываем ф-цию
				if (item != undefined)	
				{
					var func:Function =  item.func;
					var scope = item.scope;
					func.call(scope,xmlNode);
				}
		}
		// очищаем список. если надо( по умолчанию не очищаем) или если это корневой xml
		if (clearAfterParse || counter==0) clear();
	}
 
 
 
}
Всего комментариев 0

Комментарии

 

 


Часовой пояс GMT +4, время: 06:38.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.