239 lines
9.3 KiB
Plaintext
239 lines
9.3 KiB
Plaintext
<cfsilent>
|
|
<!---https://www.bennadel.com/blog/461-creating-microsoft-excel-documents-with-coldfusion-and-xml.htm--->
|
|
<!---порядок колонок, как в селекте, не управляется никак
|
|
Для определения порядка колонок используется поле ATTRIBUTES.titleMap.ordinal, возможно, не самый надежный способ
|
|
Можно попробовать использовать порядок колонок в массиве query --->
|
|
<cfparam name="ATTRIBUTES.qRead" type="query"/>
|
|
<cfparam name="ATTRIBUTES.titleMap" type="struct"/><!---see ../lib/data/field_set.cfm--->
|
|
<cfparam name="ATTRIBUTES.sheetTitle" type="string" default="Sheet1"/>
|
|
<cfparam name="ATTRIBUTES.filename" type="string" default="export.xlsx"/>
|
|
<cfset AVG_SYMBOL_WIDTH=6.5/>
|
|
<cfset MAX_COL_LENGTH=30/>
|
|
|
|
<cfset qRead=ATTRIBUTES.qRead/>
|
|
|
|
<!---<cfdump var=#qRead#/>
|
|
<cfdump var=#ATTRIBUTES.titleMap#/>
|
|
|
|
<cfabort/>
|
|
--->
|
|
|
|
<!---<cfsavecontent variable="strXmlData">--->
|
|
|
|
</cfsilent><cfheader
|
|
name="content-disposition"
|
|
value="attachment; filename=#ATTRIBUTES.filename#"
|
|
/><cfcontent
|
|
type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
/><cfoutput><?xml version="1.0"?>
|
|
<?mso-application progid="Excel.Sheet"?>
|
|
<!---
|
|
This is the Workbook root element. This element
|
|
stores characteristics and properties of the
|
|
workbook, such as the namespaces used in
|
|
SpreadsheetML.
|
|
--->
|
|
<Workbook
|
|
xmlns="urn:schemas-microsoft-com:office:spreadsheet"
|
|
xmlns:o="urn:schemas-microsoft-com:office:office"
|
|
xmlns:x="urn:schemas-microsoft-com:office:excel"
|
|
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
|
|
xmlns:html="http://www.w3.org/TR/REC-html40">
|
|
<!---
|
|
The first child element of the WorkBook element
|
|
is DocumentProperties. Office documents store
|
|
metadata related to the document—for example,
|
|
the author name, company, creation date, and
|
|
more in the DocumentProperties element.
|
|
--->
|
|
<DocumentProperties
|
|
xmlns="urn:schemas-microsoft-com:office:office">
|
|
<Author>xls-generator</Author>
|
|
<Company></Company>
|
|
</DocumentProperties>
|
|
<!---
|
|
The Styles node represents information related
|
|
to individual styles that can be used to format
|
|
components of the workbook.
|
|
--->
|
|
<Styles>
|
|
<!--- Basic format used by all cells. --->
|
|
<Style ss:ID="Default" ss:Name="Normal">
|
|
<Alignment ss:Vertical="Top"/>
|
|
<Borders/>
|
|
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11"/>
|
|
<Interior/>
|
|
<NumberFormat/>
|
|
<Protection/>
|
|
</Style>
|
|
<Style ss:ID="Th">
|
|
<Alignment ss:Horizontal="Center" ss:Vertical="Top"/>
|
|
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11" ss:Bold="1"/>
|
|
</Style>
|
|
<Style ss:ID="Int">
|
|
<NumberFormat ss:Format="0" />
|
|
</Style>
|
|
<Style ss:ID="DateTime">
|
|
<NumberFormat ss:Format="dd/mm/yyyy\ hh:mm;@"/>
|
|
</Style>
|
|
<!---
|
|
<Style ss:ID="ShortDate">
|
|
<NumberFormat ss:Format="[ENG][$-409]d\-mmm\-yyyy;@" />
|
|
</Style>
|
|
|
|
<Style ss:ID="YesNo">
|
|
<NumberFormat ss:Format="Yes/No" />
|
|
</Style>
|
|
--->
|
|
</Styles>
|
|
<!---
|
|
This defines the first worksheeet and it's name.
|
|
We are only using one worksheet in this example,
|
|
but you could add more Worksheet nodes after
|
|
this one for multiple tabs. The "Name" attribute
|
|
here is the name that shows up in the tab.
|
|
--->
|
|
<Worksheet ss:Name="#ATTRIBUTES.sheetTitle#">
|
|
<Table
|
|
<!---
|
|
We need a column for each column of the
|
|
query. This attribute is required to be
|
|
correct. If the value here does NOT
|
|
match the data in Excel file, the
|
|
document will not render properly.
|
|
--->
|
|
ss:ExpandedColumnCount="#ListLen(qRead.ColumnList)#"
|
|
<!---
|
|
We need a row for every query record
|
|
plus one for the header row. Again, if
|
|
this value does not match what is in the
|
|
document, the excel file will not
|
|
render properly.
|
|
--->
|
|
ss:ExpandedRowCount="#(qRead.RecordCount + 1)#"
|
|
x:FullColumns="1"
|
|
x:FullRows="1">
|
|
<!---
|
|
Here, we can define general properties
|
|
regarding each column in the data output.
|
|
|
|
<Column ss:Index="1" ss:Width="30" />
|
|
<Column ss:Index="2" ss:Width="100" />
|
|
<Column ss:Index="3" ss:Width="42" />
|
|
<Column ss:Index="4" ss:Width="84" />
|
|
<Column ss:Index="5" ss:Width="66" />
|
|
<Column ss:Index="6" ss:Width="70" />--->
|
|
|
|
<cfsilent>
|
|
<cfset columns=arrayNew(1)/>
|
|
<cfset i=1/>
|
|
<cfloop struct=#ATTRIBUTES.titleMap# item="field">
|
|
<cfset col=structNew()/>
|
|
<cfset fieldSpec=structFind(ATTRIBUTES.titleMap, field)/>
|
|
<cfset col.name=field/>
|
|
|
|
<cfset col.title=fieldSpec.title/>
|
|
<cfif len(col.title) EQ 0>
|
|
<cfset col.title=col.name/>
|
|
</cfif>
|
|
<cfset col.titleLength=len(col.title)/>
|
|
|
|
<cfquery name="qLen" dbtype="query">
|
|
select coalesce(max(length(#field#)),0) as maxlen from qRead
|
|
</cfquery>
|
|
<cfset col.length=max(col.titleLength, qLen.maxLen)/>
|
|
|
|
<cfset col.cfSqlType="CF_SQL_VARCHAR"/>
|
|
<cfif structKeyExists(fieldSpec,"cfSqlType")>
|
|
<cfset col.cfSqlType=#fieldSpec.cfSqlType#/>
|
|
</cfif>
|
|
|
|
<cfswitch expression=#col.cfSqlType#><!---should use ## around variable name--->
|
|
<cfcase value="CF_SQL_BIGINT,CF_SQL_INTEGER,CF_SQL_SMALLINT,CF_SQL_TINYINT,CF_SQL_BIT,CF_SQL_NUMERIC,CF_SQL_DECIMAL,CF_SQL_REAL,CF_SQL_FLOAT,CF_SQL_DOUBLE">
|
|
<cfset col.ssType="Number"/>
|
|
</cfcase>
|
|
<cfcase value="CF_SQL_TIMESTAMP,CF_SQL_DATE,CF_SQL_TIME,CF_SQL_DATETIME">
|
|
<cfset col.ssType="DateTime"/>
|
|
</cfcase>
|
|
<cfdefaultcase>
|
|
<cfset col.ssType="String"/>
|
|
</cfdefaultcase>
|
|
</cfswitch>
|
|
|
|
<cfset columns[fieldSpec.ordinal]=col/><!---new col created at each iteration, so we have valid references--->
|
|
<cfset i=i+1/>
|
|
</cfloop>
|
|
</cfsilent>
|
|
|
|
<cfloop from=1 to=#arrayLen(columns)# index="i">
|
|
<cfif columns[i].ssType EQ "DateTime"><!--- timestamp string representation is too long, --->
|
|
<Column ss:Index="#i#" ss:Width="#round(min(columns[i].titleLength, MAX_COL_LENGTH)*AVG_SYMBOL_WIDTH)#" ss:AutoFitWidth="1"/>
|
|
<cfelse>
|
|
<Column ss:Index="#i#" ss:Width="#round(min(columns[i].length, MAX_COL_LENGTH)*AVG_SYMBOL_WIDTH)#" ss:AutoFitWidth="1"/>
|
|
</cfif>
|
|
</cfloop>
|
|
<!---
|
|
This is our header row. All cells in the
|
|
header row will be of type string.
|
|
--->
|
|
<Row>
|
|
<cfloop from=1 to=#arrayLen(columns)# index="i">
|
|
<Cell ss:StyleID="Th">
|
|
<Data ss:Type="String">#columns[i].title#</Data>
|
|
</Cell>
|
|
</cfloop>
|
|
</Row>
|
|
|
|
<cfflush/>
|
|
|
|
<cfloop query=#qRead#><!---
|
|
---><Row><!---
|
|
---><cfloop from=1 to=#ArrayLen(columns)# index="i"><!---
|
|
---><cfset field=columns[i].name/><!---
|
|
---><Cell<cfif columns[i].ssType EQ "DateTime"> ss:StyleID="DateTime"</cfif>><!---
|
|
---><cfif len(qRead[field])><Data ss:Type="#columns[i].ssType#"><!---no extra whitespace allowed here---><!---
|
|
---><cfswitch expression=#columns[i].ssType#><!---
|
|
---><cfcase value="DateTime"><!---
|
|
--->#dateFormat(qRead[field],"YYYY-MM-DD")#T#timeFormat(qRead[field],"HH:mm:ss.l")#<!---
|
|
---></cfcase><!---
|
|
---><cfcase value="Number"><!---
|
|
--->#qRead[field]#<!---
|
|
---></cfcase><!---
|
|
---><cfdefaultcase><!---
|
|
---><![CDATA[#request.clean4CDATA(qRead[field])#]]><!---
|
|
---></cfdefaultcase><!---
|
|
---></cfswitch><!---
|
|
---></Data></cfif><!---
|
|
---></Cell><!---
|
|
---></cfloop><!---
|
|
---></Row><!---
|
|
---></cfloop><!---
|
|
|
|
---></Table>
|
|
|
|
</Worksheet>
|
|
|
|
</Workbook>
|
|
|
|
</cfoutput>
|
|
<!---</cfsavecontent>--->
|
|
|
|
<!---
|
|
Define the way in which the browser should interpret
|
|
the content that we are about to stream.
|
|
--->
|
|
<!---<cfheader
|
|
name="content-disposition"
|
|
value="attachment; filename=#ATTRIBUTES.filename#"
|
|
/>--->
|
|
|
|
<!---
|
|
When streaming the Excel XML data, trim the data and
|
|
replace all the inter-tag white space. No need to stream
|
|
any more content than we have to..ReplaceAll( '>\s+', '>' ).ReplaceAll( '\s+<', '<' )
|
|
--->
|
|
<!---<cfcontent
|
|
type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
variable="#ToBinary( ToBase64( strXmlData.Trim()))#"
|
|
/>---><!---<cfabort/>--->
|
|
<cfexit method="exittag"/> |