blob: 7712aedf1949697ced21e617907bf68a8a1e1427 [file] [log] [blame]
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.data.csv.CsvStore");
dojo.require("dojo.data.Read");
dojo.require("dojo.lang.assert");
dojo.declare("dojo.data.csv.CsvStore", dojo.data.Read, {
/* summary:
* The CsvStore implements the dojo.data.Read API.
*/
/* examples:
* var csvStore = new dojo.data.csv.CsvStore({url:"movies.csv");
* var csvStore = new dojo.data.csv.CsvStore({url:"http://example.com/movies.csv");
* var fileContents = dojo.hostenv.getText("movies.csv");
* var csvStore = new dojo.data.csv.CsvStore({string:fileContents);
*/
initializer:
function(/* object */ keywordParameters) {
// keywordParameters: {string: String, url: String}
this._arrayOfItems = [];
this._loadFinished = false;
this._csvFileUrl = keywordParameters["url"];
this._csvFileContents = keywordParameters["string"];
},
get:
function(/* item */ item, /* attribute or attribute-name-string */ attribute, /* value? */ defaultValue) {
// summary: See dojo.data.Read.get()
var attributeValue = item[attribute] || defaultValue;
return attributeValue; // a literal, an item, null, or undefined (never an array)
},
getValues:
function(/* item */ item, /* attribute or attribute-name-string */ attribute) {
// summary: See dojo.data.Read.getValues()
var array = [this.get(item, attribute)];
return array; // an array that may contain literals and items
},
getAttributes:
function(/* item */ item) {
// summary: See dojo.data.Read.getAttributes()
var array = this._arrayOfKeys;
return array; // array
},
hasAttribute:
function(/* item */ item, /* attribute or attribute-name-string */ attribute) {
// summary: See dojo.data.Read.hasAttribute()
for (var i in this._arrayOfKeys) {
if (this._arrayOfKeys[i] == attribute) {
return true;
}
}
return false; // boolean
},
hasAttributeValue:
function(/* item */ item, /* attribute or attribute-name-string */ attribute, /* anything */ value) {
// summary: See dojo.data.Read.hasAttributeValue()
return (this.get(item, attribute) == value); // boolean
},
isItem:
function(/* anything */ something) {
// summary: See dojo.data.Read.isItem()
for (var i in this._arrayOfItems) {
if (this._arrayOfItems[i] == something) {
return true;
}
}
return false; // boolean
},
find:
function(/* implementation-dependent */ query, /* object */ optionalKeywordArgs ) {
// summary: See dojo.data.Read.find()
if (!this._loadFinished) {
if (this._csvFileUrl) {
this._csvFileContents = dojo.hostenv.getText(this._csvFileUrl);
}
var arrayOfArrays = this._getArrayOfArraysFromCsvFileContents(this._csvFileContents);
if (arrayOfArrays.length == 0) {
this._arrayOfKeys = [];
} else {
this._arrayOfKeys = arrayOfArrays[0];
}
this._arrayOfItems = this._getArrayOfItemsFromArrayOfArrays(arrayOfArrays);
}
var result = new dojo.data.csv.Result(this._arrayOfItems, this);
return result; // dojo.data.csv.Result
},
getIdentity:
function(/* item */ item) {
// summary: See dojo.data.Read.getIdentity()
for (var i in this._arrayOfItems) {
if (this._arrayOfItems[i] == item) {
return i;
}
}
return null; // boolean
},
getByIdentity:
function(/* string */ id) {
// summary: See dojo.data.Read.getByIdentity()
var i = parseInt(id);
if (i < this._arrayOfItems.length) {
return this._arrayOfItems[i];
} else {
return null;
}
},
// -------------------------------------------------------------------
// Private methods
_getArrayOfArraysFromCsvFileContents:
function(/* string */ csvFileContents) {
/* summary:
* Parses a string of CSV records into a nested array structure.
* description:
* Given a string containing CSV records, this method parses
* the string and returns a data structure containing the parsed
* content. The data structure we return is an array of length
* R, where R is the number of rows (lines) in the CSV data. The
* return array contains one sub-array for each CSV line, and each
* sub-array contains C string values, where C is the number of
* columns in the CSV data.
*/
/* example:
* For example, given this CSV string as input:
* "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott"
* We will return this data structure:
* [["Title", "Year", "Producer"]
* ["Alien", "1979", "Ridley Scott"],
* ["Blade Runner", "1982", "Ridley Scott"]]
*/
dojo.lang.assertType(csvFileContents, String);
var lineEndingCharacters = new RegExp("\r\n|\n|\r");
var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g');
var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g');
var doubleQuotes = new RegExp('""','g');
var arrayOfOutputRecords = [];
var arrayOfInputLines = csvFileContents.split(lineEndingCharacters);
for (var i in arrayOfInputLines) {
var singleLine = arrayOfInputLines[i];
if (singleLine.length > 0) {
var listOfFields = singleLine.split(',');
var j = 0;
while (j < listOfFields.length) {
var space_field_space = listOfFields[j];
var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace
var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace
var firstChar = field.charAt(0);
var lastChar = field.charAt(field.length - 1);
var secondToLastChar = field.charAt(field.length - 2);
var thirdToLastChar = field.charAt(field.length - 3);
if ((firstChar == '"') &&
((lastChar != '"') ||
((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')) )) {
if (j+1 === listOfFields.length) {
// alert("The last field in record " + i + " is corrupted:\n" + field);
return null;
}
var nextField = listOfFields[j+1];
listOfFields[j] = field_space + ',' + nextField;
listOfFields.splice(j+1, 1); // delete element [j+1] from the list
} else {
if ((firstChar == '"') && (lastChar == '"')) {
field = field.slice(1, (field.length - 1)); // trim the " characters off the ends
field = field.replace(doubleQuotes, '"'); // replace "" with "
}
listOfFields[j] = field;
j += 1;
}
}
arrayOfOutputRecords.push(listOfFields);
}
}
return arrayOfOutputRecords; // Array
},
_getArrayOfItemsFromArrayOfArrays:
function(/* array */ arrayOfArrays) {
/* summary:
* Converts a nested array structure into an array of keyword objects.
*/
/* example:
* For example, given this as input:
* [["Title", "Year", "Producer"]
* ["Alien", "1979", "Ridley Scott"],
* ["Blade Runner", "1982", "Ridley Scott"]]
* We will return this as output:
* [{"Title":"Alien", "Year":"1979", "Producer":"Ridley Scott"},
* {"Title":"Blade Runner", "Year":"1982", "Producer":"Ridley Scott"}]
*/
dojo.lang.assertType(arrayOfArrays, Array);
var arrayOfItems = [];
if (arrayOfArrays.length > 1) {
var arrayOfKeys = arrayOfArrays[0];
for (var i = 1; i < arrayOfArrays.length; ++i) {
var row = arrayOfArrays[i];
var item = {};
for (var j in row) {
var value = row[j];
var key = arrayOfKeys[j];
item[key] = value;
}
arrayOfItems.push(item);
}
}
return arrayOfItems; // Array
}
});