Recently, I needed a way to export data from Adobe Flex’s AdvancedDataGrid control to CSV-formatted files for use in Microsoft Excel. Since Flex did not provide a native method, I looked into some existing third-party libraries. Those did not work out, so I ended up building my own AdvancedDataGrid CSV export utility class.
I first experimented with the excellent AlivePDF library. I had used AlivePDF in the past to…well…create PDFs. One of the things I remembered from using it was that there was CSV export functionality. But after spending some time experimenting, I was disappointed to find it required quite a bit of overhead and would not be able to fully satisfy my needs. Next, I turned my attention towards the AS3XLS library. From what I could gather, the library seems like what you’d want if you were trying to read & write native Excel files, but it didn’t provide CSV support.
So, I started searching the intertubes for another option. I found a great post by Abdul Qabiz, demonstrating a home baked solution he had come up with. The code he presented was quite dated (it was written for Flex 2, targeting the DataGrid control) and was missing some features I needed. However, it was exactly what I needed as a starting point. Learning from what he provided, I rolled my own solution that provided everything I was looking for.
Below is the AdvancedDataGrid CSV export utility class I came up with. It compiles in Flex 3.5, Flex 3.6 and Flex 4.5, handles grouped column headers, can double-quote values, and is capable of saving the CSV data of any language to a file (through the use of UTF-16 encoding). I am posting this simple class in case somebody else might find it useful. If you do, please leave a comment. Also, let me know if you find ways to improve it!
Note: The final version of the code uses a tab as the default CSV delimiter. This is due to a limitation in Excel when dealing with a comma-separated value file in UTF-16/Unicode encoding. Despite the use of a tab character, the format of the file is still viewed as a “CSV”. :-)
Download the code.
CSVUtil.as:
package net.onyxmueller.util |
{ |
import flash.net.FileReference; |
import flash.utils.ByteArray; |
|
import mx.collections.ICollectionView; |
import mx.collections.IViewCursor; |
import mx.controls.AdvancedDataGrid; |
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn; |
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumnGroup; |
|
public class CSVUtil |
{ |
private var _csvSeparator:String; |
private var _lineSeparator:String; |
private var _doubleQuoteValues:Boolean; |
private var _doubleQuoteRexExPattern:RegExp = /\"/g; |
private var _encoding:String; |
|
public function CSVUtil(csvSeparator:String = "\t", lineSeparator:String = "\n", doubleQuoteValues:Boolean = true) |
{ |
_csvSeparator = csvSeparator; |
_lineSeparator = lineSeparator; |
_doubleQuoteValues = doubleQuoteValues; |
} |
|
public function formatAsCSVString(items:Array):String |
{ |
if (_doubleQuoteValues) |
{ |
// escape any existing double quotes then place double quotes around values |
for (var i:int = 0; i < items.length; i++) |
{ |
items[i] = items[i] ? items[i].replace(_doubleQuoteRexExPattern, "\"\"") : ""; |
items[i] = "\"" + items[i] + "\""; |
} |
} |
return items.join(_csvSeparator) + _lineSeparator; |
} |
|
public function advancedDataGridToCSVString(dg:AdvancedDataGrid):String |
{ |
var headerCSV:String = ""; |
var headerItems:Array; |
var dataCSV:String = ""; |
var dataItems:Array; |
var columns:Array = dg.groupedColumns ? dg.groupedColumns : dg.columns; |
var column:AdvancedDataGridColumn; |
var headerGenerated:Boolean = false; |
var cursor:IViewCursor = (dg.dataProvider as ICollectionView).createCursor(); |
|
// loop through rows |
while (!cursor.afterLast) |
{ |
var obj:Object = null; |
obj = cursor.current; |
dataItems = new Array(); |
headerItems = new Array(); |
// loop through all columns for the row |
for each (column in columns) |
{ |
// if the column is not visible or the header text is not defined (e.g., a column used for a graphic), |
// do not include it in the CSV dump |
if (!column.visible || !column.headerText) |
continue; |
|
// depending on whether the current column is a group or not, export the data differently |
if (column is AdvancedDataGridColumnGroup) |
{ |
for each (var subColumn:AdvancedDataGridColumn in (column as AdvancedDataGridColumnGroup).children) |
{ |
// if the sub-column is not visible or the header text is not defined (e.g., a column used for a graphic), |
// do not include it in the CSV dump |
if (!subColumn.visible || !subColumn.headerText) |
continue; |
dataItems.push(obj ? subColumn.itemToLabel(obj) : ""); |
if (!headerGenerated) |
headerItems.push(column.headerText + ": " + subColumn.headerText); |
} |
} |
else |
{ |
dataItems.push( obj ? column.itemToLabel(obj) : ""); |
if (!headerGenerated) |
headerItems.push(column.headerText); |
} |
} |
// append a CSV generated line of our data |
dataCSV += formatAsCSVString(dataItems); |
// if our header CSV has not been generated yet, do so; this should only occur once |
if (!headerGenerated) |
{ |
headerCSV = formatAsCSVString(headerItems); |
headerGenerated = true; |
} |
// move to our next item |
cursor.moveNext(); |
} |
|
// set references to null: |
headerItems = null; |
dataItems = null; |
columns = null; |
column = null; |
cursor = null; |
|
// return combined string |
return headerCSV + dataCSV; |
} |
|
public function saveAdvancedDataGridAsCSVFile(dg:AdvancedDataGrid, fileName:String, encoding:String = "utf-16"):void |
{ |
var csvString:String = advancedDataGridToCSVString(dg); |
var bytes:ByteArray = new ByteArray(); |
// if using UTF-16, prefix file with BOM (little-endian) |
if (encoding == "utf-16") |
{ |
bytes.writeByte(0xFF); |
bytes.writeByte(0xFE); |
bytes.writeMultiByte(csvString, encoding); |
} |
else |
bytes.writeMultiByte(csvString, encoding); |
// prompt the user with a save location |
// note: FileReference requires a minimum flash player version of 10 |
var fileReference:FileReference = new FileReference(); |
fileReference.save(bytes, fileName); |
fileReference = null; |
} |
} |
} |