BoxLang 🚀 A New JVM Dynamic Language Learn More...
Standalone library for working with spreadsheets and CSV in CFML (Lucee and Adobe ColdFusion), supporting all of ColdFusion's native spreadsheet functionality and much more besides.
Note that this is not an extension or package, so does not need to be installed. To use it, simply copy the files/folders to a location where Spreadsheet.cfc
can be called by your application code.
The following are the essential files/folders you will need depending on which CFML engine you are using:
helpers/
objects/
lib-osgi.jar
osgiLoader.cfc
Spreadsheet.cfc
helpers/
javaLoader/
lib/
objects/
Spreadsheet.cfc
The following example assumes the file containing the script is in the same directory as the folder containing the spreadsheet library files, i.e.:
<cfscript>
spreadsheet = New spreadsheetLibrary.Spreadsheet();
data = QueryNew( "First,Last", "VarChar, VarChar", [ [ "Susi", "Sorglos" ], [ "Frumpo", "McNugget" ] ] );
workbook = spreadsheet.new();
spreadsheet.addRows( workbook, data );
spreadsheet.write( workbook, "c:/temp/data.xls" );
</cfscript>
When instantiating the library, the init()
method must be called. This will happen automatically if you use the New
keyword:
spreadsheet = New spreadsheetLibrary.Spreadsheet();
If using CreateObject()
then you must call init()
explicitly:
spreadsheet = CreateObject( "component", "spreadsheetLibrary.Spreadsheet" ).init();
You may wish to place the spreadsheet library files in a central location with an application mapping, and instantiate the component using its dot path (e.g. New myLibrary.spreadsheet.Spreadsheet();
).
How to create mappings (StackOverflow).
In Adobe ColdFusion, the SpreadsheetRead()
script function is limited to just returning a spreadsheet object, whereas the <cfspreadsheet action="read">
tag has a range of options for reading and returning data from a spreadsheet file.
The read()
method in this library allows you to read a spreadsheet file into a query and return that instead of a spreadsheet object. It includes all of the options available in <cfspreadsheet action="read">
.
<cfscript>
myQuery = spreadsheet.read( src=mypath, format="query" );
</cfscript>
The read()
method also features the following additional options not available in ColdFusion or the Spreadsheet Extension:
fillMergedCellsWithVisibleValue
includeHiddenColumns
includeRichTextFormatting
password
to open encrypted spreadsheetscsvDelimiter
queryColumnTypes
From version 3, multiple calls can be chained together, simplifying your code into a more expressive syntax.
spreadsheet.newChainable( "xlsx" )
.addRows( data )
.formatRow( { bold: true }, 1 )
.write( filepath );
The following international date masks are used by default to read and write cell values formatted as dates:
yyyy-mm-dd
hh:mm: ss
yyyy-mm-dd hh:mm: ss
An additional mask is used to output datetime values from the read()
method into HTML or CSV formats:
yyyy-mm-dd HH:nn: ss
NB: Do not confuse DATETIME
and TIMESTAMP
. In general you should override the TIMESTAMP
mask.
Each of these can be overridden by passing in a struct including the value(s) to be overridden when instantiating the Spreadsheet component. For example:
<cfscript>
spreadsheet = New spreadsheetLibrary.Spreadsheet( dateFormats={ DATE: "mm/dd/yyyy" } );
</cfscript>
Or by using the setDateFormats()
method on an existing instance.
<cfscript>
spreadsheet = New spreadsheetLibrary.Spreadsheet();
spreadsheet.setDateFormats( { DATE: "mm/dd/yyyy" } );
</cfscript>
While the above will set the library defaults, you can format cells with specific masks using the dataFormat
attribute which can be passed to formatCell and the other formatting methods, as part of the format
argument:
// display datetime value with millisecond precision
spreadsheet.formatColumn( workbook , { dataformat: "yyyy-mm-dd hh:mm: ss.000" }, 1 );
From version 2.14.0, Lucee loads the POI and other required java libraries using OSGi. This is not yet supported with Adobe ColdFusion which by default uses an included version of Mark Mandel's JavaLoader.
For more details and options see: Loading the POI java libraries
You can also download this library through CommandBox/Forgebox.
box install spreadsheet-cfml
It will download the files into a modules directory and can be used just the same as downloading the files manually.
If using ColdBox you can use either of the WireBox bindings like so:
spreadsheet = wirebox.getInstance( "Spreadsheet@spreadsheet-cfml" );
spreadsheet = wirebox.getInstance( "Spreadsheet CFML" );
The automated tests require TestBox 5.0 or later. You will need to create an application mapping for /testbox
The code was originally adapted from the work of TeamCfAdvance. Ben Nadel's POI Utility was also used as a basis for parts of the read
functionality. Header/Footer image functionality is based on code by Axel Richter.
JavaLoader is by Mark Mandel.
Copyright (c) 2015-2024 Julian Halliwell
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Enhancements
Maintenance -#375 Upgrade excel-streaming-reader to 5.0.2
Enhancements
Maintenance -#371 Upgrade excel-streaming-reader to 4.3.1
Breaking changes
Enhancements
Enhancements -#346 Add writeCsv()
Fixes -#347/#348 Avoid Perl/Java regex engine incompatibilities
Maintenance -#349 Upgrade POI to 5.2.5 -#350 Upgrade excel-streaming-reader to 4.2.1
Enhancements
Fixes
Maintenance
Maintenance
Enhancements
Enhancements
Fixes
Enhancements
Fixes
Maintenance
Enhancements
Fixes
#310 Upgrade excel-streaming-reader to 4.0.4
Enhancements
Fixes
Security Update
Enhancements
Fixes
Enhancements
Fixes
Breaking changes
Enhancements
Fixes
Enhancements
workbookFromQuery()
isCsvOrTextFile
support for .tsv filesFixes
Enhancements
Fixes
Enhancements
Fixes
Enhancements
Fixes
Enhancements
Fixes
Enhancements
Fixes
Enhancements
Fixes
Enhancements
Fixes
Enhancements
getColumnWidth()
and getColumnWidthInPixels()
Fixes
engineSupportsEncryption
environment key. Use engineSupportsWriteEncryption
includeQueryColumnNames
in addRows()
produces invalid xlsxaddRow()
and addRows()
addRows()
doesn't apply column offset to header row when using includeQueryColumnNames
setActiveSheet()
.Breaking changes
CreateObject
engineSupportsDynamicClassLoading
variable completely, since it is meaninglessEnhancements
write()
outputstream locking.dumpPathToClass()
diagnostic toolFixes
append()
BIF instead of java add()
setCellValue()
test on ACF2016+loadColdFusionClassPath
setting (add commons-codec jar to lib)getRowCount()
addAutofilter()
addPageBreaks()
addPrintGridlines()
and removePrintGuidelines()
getCellFormat()
should be a descriptive stringgetCellFormat()
and formatting testsquoteprefixed
to cell formatting optionshideRow()
, showRow()
and isRowHidden()
isColumnHidden()
and tests for hideColumn()
and showColumn()
setCellValue()
getCellType()
csvToQuery()
to be called with positional argumentsworkbookFromCsv()
csvToQuery()
for conveniencegetEnvironment()
method to return current environment details/settingscellstyle
setters.info()
method instead of a workbook objectgetBold()
/setBold()
.setSheetPrintOrientation()
to catch errors.setSheetPrintOrientation()
.buildCellStyle()
to improve performance and fix boolean issue with "bold".newXlsx()
and newXls()
as aliases for new( xmlFormat=true/false )
readBinary()
in 0.8.2 causes MS Excel to crashreadBinary()
by using java ByteBuffer.addRow()
and other methods.AddRow()
causing "maximum number of cell styles was exceeded" error when inserting large number of rows including dates.formatColumn()
fails when workbook contains more than 4000 rowsisSpreadsheetFile()
not working in ACF for non-spreadsheet files.isSpreadsheetFile()
and isSpreadsheetObject()
this
scope for internal method callsExpandPath()
when getting POI jar paths for JavaLoadergetColumnCount()
read()
src
file is not a spreadsheet.setReadOnly()
method for binary workbooks (only)write()
provides whole file encryption for XML spreadsheet files (only)setRepeatingColumns()
and setRepeatingRows()
download()
function for an existing workbook object.includeQueryColumnNames
option to AddRows()
.read()
by using native Java concatenation instead of arrays which are slow in Lucee.read()
and includeRichTextFormatting
when different from the cell's base font. Better to be consistent and not support these attributes anywhere so the expectation is clear.read()
and includeRichTextFormatting
when different from the cell's base fontincludeRichTextFormatting
option in read()
results in empty span style if format not supportedincludeRichTextFormatting
option to read()
read()
to allow excluding hidden columnshideColumn()
and showColumn()
read()
read()
.fillMergedCellsWithVisibleValue
option to read()
setCellRangeValue()
emptyInvisibleCells
option to mergeCells()
deleteSheet[Number]()
in favour of removeSheet[Number]()
setActiveSheetNumber()
formatRows()
deleteRows()
deleteColumn()
and deleteColumns()
shiftColumns()
getCellValue()
and setCellValue()
formatColumn()
, formatColumns()
and formatCellRange()
isBinaryFormat()
and isXmlFormat()
mergeCells()
addFreezePane()
and addSplitPane()
addInfo()
and info()
setCellFormula()
and getCellFormula()
setColumnWidth()
setRowHeight()
setHeader()
and setFooter()
setCellComment()
and getCellComment()
addImage()
autoSizeColumn()
renameSheet()
clearCell()
and clearCellRange()
read()
method sheet
argument should now be sheetNumber
(for consistency)sheetNumber
(not sheet
or sheetIndex
).sheetName
, not sheet
.createSheet()
removeSheet()
deleteSheet()
which can delete a sheet by name or numbernew()
method ignores xmlFormat argumentShiftRows
offset argument misspelShiftRows
calls require workbook as argumenAddRow
insert argument not workingRead
method errors if no format specified. Should return workbook objectwriteFileFromQuery()
: detect if xml from file extensionexcludeHeaderRow
default=false to includeHeaderRow
, default=falseread
method
excludeHeaderRow
default from false to trueflushPoiLoader
utility methodwrite
method matching SpreadSheetWrite()
writeFileFromQuery
custom methodnew()
and then pass it to other functions. Same as ACF functions.read()
new
read
(matches cfspreadsheet action="read"
)setActiveSheet
downloadFileFromQuery
addColumn
addRow
addRows
deleteRow
formatCell
formatRow
shiftRows
readBinary
binaryFromQuery
$
box install spreadsheet-cfml