package sketchbook.data { import flash.utils.Dictionary; /** * Namespaceなどのない単純なXMLをパースする為のクラスです。 * * SimpleXMLParserにXMLのノード名毎に行うパース処理を定義する事で、 * Number, Date等といった型を考慮したスムーズな * * var np:NodeParser = new NodeParser(); * np.addNodeDefinition("items", NodeParser.ARRAY); //itemsノードを Arrayと定義 * np.addNodeDefinition("item", NodeParser.OBJECT); //itemノードをObjectと定義 * np.addNodeDefinition("title", NodeParser.STRING); //titleノードをStringと定義 * var obj:Object = np.parse(xml); */ public class SimpleXMLParser { protected var definitions:Dictionary; protected var parserDefinition:Dictionary; public static const ARRAY:String = "Array" public static const BOOLEAN:String = "Boolean" public static const DATE:String = "Date" public static const DICTIONARY:String = "Dictionary" public static const NUMBER:String = "Number" public static const OBJECT:String = "Object" public static const STRING:String = "String" /** * XMLノードを任意の関数に私、関数の処理結果を値として返す場合に用いる。 * このタイプを addParseDefinition に指定する場合、第三引数でクロージャ関数を指定する。 * function(xml:XML):Object */ public static const FUNCTION:String = "Function" /** * 文字列を任意のスプリッタで分割し、数字として格納した配列に変換する場合のタイプ。 * このタイプを addParseDefinition に指定する場合、第三引数で splitter として用いる文字を指定する。 */ public static const SPLITTED_NUMBER_ARRAY:String = "SplittedNumberArray"; /** * 文字列を任意のスプリッタで分割し、文字として格納した配列に変換する場合のタイプ。 * このタイプを addParseDefinition に指定する場合、第三引数で splitter として用いる文字を指定する。 */ public static const SPLITTED_STRING_ARRAY:String = "SplittedStringArray"; public static const CLASS_INSTANCE:String = "ClassInstance"; public function SimpleXMLParser() { definitions = new Dictionary(); parserDefinition = new Dictionary(); //primitive definition addParserDefinition(SimpleXMLParser.ARRAY, _parseAsArray); addParserDefinition(SimpleXMLParser.BOOLEAN, _parseAsBoolean); addParserDefinition(SimpleXMLParser.DATE, _parseAsDate); addParserDefinition(SimpleXMLParser.DICTIONARY, _parseAsDictionary); addParserDefinition(SimpleXMLParser.NUMBER, _parseAsNumber); addParserDefinition(SimpleXMLParser.OBJECT, _parseAsObject); addParserDefinition(SimpleXMLParser.STRING, _parseAsString); //Special Parser definition addParserDefinition(SimpleXMLParser.FUNCTION, _parseWithFunction); addParserDefinition(SimpleXMLParser.CLASS_INSTANCE, _parseAsClassInstance); addParserDefinition(SimpleXMLParser.SPLITTED_NUMBER_ARRAY, _parseAsSplittedNumberArray); addParserDefinition(SimpleXMLParser.SPLITTED_STRING_ARRAY, _parseAsSplittedStringArray); } /** * パース時の任意の名称のノードの扱いを定義します。 * ノードの定義には以下の3つの方法があります。 * * 1 プリミティブ型で扱う場合: ARRAY,BOOLEAN,DATE等の定数を第二引数に渡す。 * 2 属性等を反映する場合: XMLを受け取り、パース結果を返すクロージャを第二引数に渡す。 * 3 特定のノード以下でのみパースのルールを変更したい場合: NodeParserインスタンスを第二引数に渡す。 */ public function addNodeDefinition(node:String, type:*, ...args):void { definitions[node] = {type:type, args:args}; } protected function hasParserDefinition(nodeName:String):Boolean { return nodeName in definitions; } /** * カスタムパース関数を定義します。 * 第一引数には、addNodeDefinitionで使いたいパーサータイプ名 * 第二引数には、実際にパースを行う関数 function(xml:XML, rule:Object):Object の参照を渡します。 * */ public function addParserDefinition(key:String, func:Function):void { parserDefinition[key] = func; } public function parse(xml:XML):Object { if (xml==null) { return null; } var nodeName:String = xml.name(); var nodeValue:String = xml.text(); if (hasParserDefinition(nodeName)) { var parseRule:Object = definitions[nodeName]; var type:Object = parseRule.type; var func:Function = parserDefinition[type]; if(func!=null) { return func(xml, parseRule); } } return null; } /* -------------------------------------------------------------- primitive parsers -------------------------------------------------------------- */ protected function _parseAsArray(xml:XML, rule:Object):Array { var ar:Array = []; var cnds:XMLList = xml.children(); var n:int = cnds.length(); for(var i:int=0; i