⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 graphmlconverter.as

📁 用于flash/flex的 as3的 2D图形图像图表的动态生成
💻 AS
字号:
package flare.data.converters
{
	import flare.data.DataField;
	import flare.data.DataSchema;
	import flare.data.DataSet;
	import flare.data.DataTable;
	import flare.data.DataUtil;
	
	import flash.utils.ByteArray;
	import flash.utils.IDataInput;
	import flash.utils.IDataOutput;

	/**
	 * Converts data between GraphML markup and flare DataSet instances.
	 * <a href="http://graphml.graphdrawing.org/">GraphML</a> is a
	 * standardized XML format supporting graph structure and typed data
	 * schemas for both nodes and edges.
	 */
	public class GraphMLConverter implements IDataConverter
	{    
		// -- reader ----------------------------------------------------------
		
		/** @inheritDoc */
		public function read(input:IDataInput, schema:DataSchema=null):DataSet
		{
			var str:String = input.readUTFBytes(input.bytesAvailable);
			var idx:int = str.indexOf(GRAPHML);
			if (idx > 0) {
				str = str.substr(0, idx+GRAPHML.length) + 
					str.substring(str.indexOf(">", idx));
			}
			return parse(XML(str), schema);
		}
		
		/**
		 * Parses a GraphML XML object into a DataSet instance.
		 * @param graphml the XML object containing GraphML markup
		 * @param schema a DataSchema (typically null, as GraphML contains
		 *  schema information)
		 * @return the parsed DataSet instance
		 */
		public function parse(graphml:XML, schema:DataSchema=null):DataSet
		{
			var lookup:Object = {};
			var nodes:Array = [], n:Object;
			var edges:Array = [], e:Object;
			var id:String, sid:String, tid:String;
			var def:Object, type:int;
			var group:String, attrName:String, attrType:String;
			
			var nodeSchema:DataSchema = new DataSchema();
			var edgeSchema:DataSchema = new DataSchema();
			var schema:DataSchema;
			
			// set schema defaults
			nodeSchema.addField(new DataField(ID, DataUtil.STRING));
			edgeSchema.addField(new DataField(ID, DataUtil.STRING));
			edgeSchema.addField(new DataField(SOURCE, DataUtil.STRING));
			edgeSchema.addField(new DataField(TARGET, DataUtil.STRING));
			edgeSchema.addField(new DataField(DIRECTED, DataUtil.BOOLEAN,
									DIRECTED == graphml.graph.@edgedefault));
			
			// parse data schema
			for each (var key:XML in graphml..key) {
				id       = key.@[ID].toString();
				group    = key.@[FOR].toString();
				attrName = key.@[ATTRNAME].toString();
				type     = toType(key.@[ATTRTYPE].toString());
				def = key[DEFAULT].toString();
				def = def != null && def.length > 0
					? DataUtil.parseValue(def, type) : null;
				
				schema = (group==EDGE ? edgeSchema : nodeSchema);
				schema.addField(new DataField(attrName, type, def, id));
			}
			
			// parse nodes
			for each (var node:XML in graphml..node) {
				id = node.@[ID].toString();
				lookup[id] = (n = parseData(node, nodeSchema));
				nodes.push(n);
			}
			
			// parse edges
			for each (var edge:XML in graphml..edge) {
				id  = edge.@[ID].toString();
				sid = edge.@[SOURCE].toString();
				tid = edge.@[TARGET].toString();
				
				// error checking
				if (!lookup.hasOwnProperty(sid))
					error("Edge "+id+" references unknown node: "+sid);
				if (!lookup.hasOwnProperty(tid))
					error("Edge "+id+" references unknown node: "+tid);
								
				edges.push(e = parseData(edge, edgeSchema));
			}
			
			return new DataSet(
				new DataTable(nodes, nodeSchema),
				new DataTable(edges, edgeSchema)
			);
		}
		
		private function parseData(node:XML, schema:DataSchema):Object {
			var n:Object = {};
			var name:String, field:DataField, value:Object;
			
			// set default values
			for (var i:int=0; i<schema.numFields; ++i) {
				field = schema.getFieldAt(i);
				n[field.name] = field.defaultValue;
			}
			
			// get attribute values
			for each (var attr:XML in node.@*) {
				name = attr.name().toString();
				field = schema.getFieldByName(name);
				n[name] = DataUtil.parseValue(attr[0].toString(), field.type);
			}
			
			// get data values in XML
			for each (var data:XML in node.data) {
				field = schema.getFieldById(data.@[KEY].toString());
				name = field.name;
				n[name] = DataUtil.parseValue(data[0].toString(), field.type);
			}
			
			return n;
		}

		// -- writer ----------------------------------------------------------
		
		/** @inheritDoc */
		public function write(data:DataSet, output:IDataOutput=null):IDataOutput
		{			
			// init GraphML
			var graphml:XML = new XML(GRAPHML_HEADER);
			
			// add schema
			graphml = addSchema(graphml, data.nodes.schema, NODE, NODE_ATTR);
			graphml = addSchema(graphml, data.edges.schema, EDGE, EDGE_ATTR);
			
			// add graph data
			var graph:XML = new XML(<graph/>);
			var ed:Object = data.edges.schema.getFieldByName(DIRECTED).defaultValue;
			graph.@[EDGEDEF] = ed==DIRECTED ? DIRECTED : UNDIRECTED;
			addData(graph, data.nodes.data, data.nodes.schema, NODE, NODE_ATTR);
			addData(graph, data.edges.data, data.edges.schema, EDGE, EDGE_ATTR);
			graphml = graphml.appendChild(graph);
			
			if (output == null) output = new ByteArray();
			output.writeUTFBytes(graphml.toXMLString());
			return output;
		}
		
		private static function addSchema(xml:XML, schema:DataSchema,
			group:String, attrs:Object):XML
		{
			var field:DataField;
			
			for (var i:int=0; i<schema.numFields; ++i) {
				field = schema.getFieldAt(i);
				if (attrs.hasOwnProperty(field.name)) continue;
				
				var key:XML = new XML(<key/>);
				key.@[ID] = field.id;
				key.@[FOR] = group;
				key.@[ATTRNAME] = field.name;
				key.@[ATTRTYPE] = fromType(field.type);
			
				if (field.defaultValue != null) {
					var def:XML = new XML(<default/>);
					def.appendChild(toString(field.defaultValue, field.type));
					key.appendChild(def);
				}
				
				xml = xml.appendChild(key);
			}
			return xml;
		}
		
		private static function addData(xml:XML, tuples:Array,
			schema:DataSchema, tag:String, attrs:Object):void
		{
			for each (var tuple:Object in tuples) {
				var x:XML = new XML("<"+tag+"/>");
				
				for (var name:String in tuple) {
					var field:DataField = schema.getFieldByName(name);
					if (tuple[name] == field.defaultValue) continue;
					if (attrs.hasOwnProperty(name)) {
						// add as attribute
						x.@[name] = toString(tuple[name], field.type);
					} else {
						// add as data child tag
						var data:XML = new XML(<data/>);
						data.@[KEY] = field.id;
						data.appendChild(toString(tuple[name], field.type));
						x.appendChild(data);
					}
				}
				
				xml.appendChild(x);
			}
		}	
		
		// -- static helpers --------------------------------------------------
		
		private static function toString(o:Object, type:int):String
		{
			return o.toString(); // TODO: formatting control?
		}
		
		private static function toType(type:String):int {
			switch (type) {
				case INT:
				case INTEGER:
					return DataUtil.INT;
				case LONG:
				case FLOAT:
				case DOUBLE:
				case REAL:
					return DataUtil.NUMBER;
				case BOOLEAN:
					return DataUtil.BOOLEAN;
				case DATE:
					return DataUtil.DATE;
				case STRING:
				default:
					return DataUtil.STRING;
			}
		}
		
		private static function fromType(type:int):String {
			switch (type) {
				case DataUtil.INT: 		return INT;
				case DataUtil.BOOLEAN: 	return BOOLEAN;
				case DataUtil.NUMBER:	return DOUBLE;
				case DataUtil.DATE:		return DATE;
				case DataUtil.STRING:
				default:				return STRING;
			}
		}
		
		private static function error(msg:String):void {
			throw new Error(msg);
		}
		
		// -- constants -------------------------------------------------------
		
		private static const NODE_ATTR:Object = {
			"id":1
		}
		private static const EDGE_ATTR:Object = {
			"id":1, "directed":1, "source":1, "target":1
		};
		
		private static const GRAPHML_HEADER:String = "<graphml/>";
		//	"<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"" 
        //    +" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
        //    +" xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns"
        //    +" http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">"
        //    +"</graphml>";
        
        private static const GRAPHML:String    = "graphml";
		private static const ID:String         = "id";
	    private static const GRAPH:String      = "graph";
	    private static const EDGEDEF:String    = "edgedefault";
	    private static const DIRECTED:String   = "directed";
	    private static const UNDIRECTED:String = "undirected";
	    
	    private static const KEY:String        = "key";
	    private static const FOR:String        = "for";
	    private static const ALL:String        = "all";
	    private static const ATTRNAME:String   = "attr.name";
	    private static const ATTRTYPE:String   = "attr.type";
	    private static const DEFAULT:String    = "default";
	    
	    private static const NODE:String   = "node";
	    private static const EDGE:String   = "edge";
	    private static const SOURCE:String = "source";
	    private static const TARGET:String = "target";
	    private static const DATA:String   = "data";
	    private static const TYPE:String   = "type";
	    
	    private static const INT:String = "int";
	    private static const INTEGER:String = "integer";
	    private static const LONG:String = "long";
	    private static const FLOAT:String = "float";
	    private static const DOUBLE:String = "double";
	    private static const REAL:String = "real";
	    private static const BOOLEAN:String = "boolean";
	    private static const STRING:String = "string";
	    private static const DATE:String = "date";
		
	} // end of class GraphMLConverter
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -