1 package flare.data.converters
3 import flare.data.DataField;
4 import flare.data.DataSchema;
5 import flare.data.DataSet;
6 import flare.data.DataTable;
7 import flare.data.DataUtil;
9 import flash.utils.ByteArray;
10 import flash.utils.IDataInput;
11 import flash.utils.IDataOutput;
14 * Converts data between delimited text (e.g., tab delimited) and
15 * flare DataSet instances.
17 public class DelimitedTextConverter implements IDataConverter
19 private var _delim:String;
21 public function get delimiter():String { return _delim; }
22 public function set delimiter(d:String):void { _delim = d; }
25 * Creates a new DelimitedTextConverter.
26 * @param delim the delimiter string separating values (tab by default)
28 public function DelimitedTextConverter(delim:String="\t")
36 public function read(input:IDataInput, schema:DataSchema=null):DataSet
38 return parse(input.readUTFBytes(input.bytesAvailable), schema);
42 * Converts data from a tab-delimited string into ActionScript objects.
43 * @param input the loaded input data
44 * @param schema a data schema describing the structure of the data.
45 * Schemas are optional in many but not all cases.
46 * @param data an array in which to write the converted data objects.
47 * If this value is null, a new array will be created.
48 * @return an array of converted data objects. If the <code>data</code>
49 * argument is non-null, it is returned.
51 public function parse(text:String, schema:DataSchema=null):DataSet
53 var tuples:Array = [];
54 var lines:Array = text.split(/\r\n|\r|\n/);
57 schema = inferSchema(lines);
60 var i:int = schema.hasHeader ? 1 : 0;
61 for (; i<lines.length; ++i) {
62 var line:String = lines[i];
63 if (line.length == 0) break;
64 var tok:Array = line.split(_delim);
65 var tuple:Object = {};
66 for (var j:int=0; j<schema.numFields; ++j) {
67 var field:DataField = schema.getFieldAt(j);
68 tuple[field.name] = DataUtil.parseValue(tok[j], field.type);
72 return new DataSet(new DataTable(tuples, schema));
78 public function write(data:DataSet, output:IDataOutput=null):IDataOutput
80 if (output==null) output = new ByteArray();
81 var tuples:Array = data.nodes.data;
82 var schema:DataSchema = data.nodes.schema;
84 for each (var tuple:Object in tuples) {
85 var i:int = 0, s:String;
87 for (var name:String in tuple) {
88 if (i>0) output.writeUTFBytes(_delim);
89 output.writeUTFBytes(String(tuple[name])); // TODO: proper string formatting
93 for (;i<schema.numFields; ++i) {
94 var f:DataField = schema.getFieldAt(i);
95 if (i>0) output.writeUTFBytes(_delim);
96 output.writeUTFBytes(String(tuple[f.name])); // TODO proper string formatting
99 output.writeUTFBytes("\n");
105 * Infers the data schema by checking values of the input data.
106 * @param lines an array of lines of input text
107 * @return the inferred schema
109 protected function inferSchema(lines:Array):DataSchema
111 var header:Array = lines[0].split(_delim);
112 var types:Array = new Array(header.length);
114 // initialize data types
115 var tok:Array = lines[1].split(_delim);
116 for (var col:int=0; col<header.length; ++col) {
117 types[col] = DataUtil.type(tok[col]);
120 // now process data to infer types
121 for (var i:int = 2; i<lines.length; ++i) {
122 tok = lines[i].split(_delim);
123 for (col=0; col<tok.length; ++col) {
124 if (types[col] == -1) continue;
125 var type:int = DataUtil.type(tok[col]);
126 if (types[col] != type) {
132 // finally, we create the schema
133 var schema:DataSchema = new DataSchema();
134 schema.hasHeader = true;
135 for (col=0; col<header.length; ++col) {
136 schema.addField(new DataField(header[col],
137 types[col]==-1 ? DataUtil.STRING : types[col]));
142 } // end of class DelimitedTextConverter