Partners AdvanCode.com: free classifieds · RSS · RSS2WAP · Toronto · driving schools · PC lessons · dating
AdvanCode Index

 

Generate Excel files

By: AdvanCode [2004-12-01]
Read: 39816 times

This article has been chosen Tutorial of the week at ASP Experts.com (Apr 29, 2002)

Generating Excel files from web pages or other applications is a major subject in many articles. I'd like to present here some solutions, part of them, already presented and well known. Some of them require MS Excel to be installed on the server, and other not.

Let's enumerate a few solutions:

A solution that require Excel to be installed is made by using Automation. Even from ASP pages it could be created external COM servers (as Excel) and use it thru automation. Some versions of IIS may require an extra setting. You can do this by writing the following code in a VBS file and execute it (for instance iis.vbs):

Set ow=GetObject("IIS://LocalHost/W3svc")

ow.Put "AspAllowOutOfProcComponents",True
ow.SetInfo

Set ow=Nothing
MsgBox "Done"
			

Then, you can create Excel objects thru automation. First, create some include files which contain the opening (OpenConnection.asp) and closing (CloseConnection.asp) of a connection and a file having all Excel constants called "excel.inc" (these values are declared in Excel type-library, which isn't available in ASP), as bellow:

<%
xlAutomatic = -4105

xlCenter=-4108
xlLeft = -4131
xlRight = -4152
xlBottom = -4107

xlNone = -4142

xlDiagonalDown = 5
xlDiagonalUp = 6
xlEdgeLeft = 7
xlEdgeTop = 8
xlEdgeBottom = 9
xlEdgeRight = 10
xlInsideVertical = 11
xlInsideHorizontal = 12

xlThin = 2
xlThick = 4
%>
			  

Then, try this code (excel1.asp):

<!--#include file = "../Include/OpenConnection.asp"-->
<!--#include file = "../Include/EXCEL.INC"-->
<HTML>
<%
Dim rsAsp
Set rsAsp = Server.CreateObject("ADODB.Recordset")

Dim ex
Set ex=Server.CreateObject("Excel.Application")

Dim fs,f
Set fs=Server.CreateObject("Scripting.FileSystemObject")
f = fs.GetBaseName(fs.GetTempName()) & ".xls"

ex.Workbooks.Add

ex.ActiveSheet.Range("E1").Value = "Something"

ex.ActiveSheet.Range("A1:C1").Select
ex.Selection.Merge
ex.Selection.Value = "Title"
ex.Selection.Interior.ColorIndex=15
ex.Selection.Font.Bold=True
ex.Selection.Font.Size=12
ex.Selection.Font.ColorIndex=2

ex.ActiveSheet.Range("A2:C2").RowHeight = 24
ex.ActiveSheet.Range("A2:C2").HorizontalAlignment = xlCenter
ex.ActiveSheet.Range("A2:C2").VerticalAlignment = xlCenter
ex.ActiveSheet.Range("A2:C2").WrapText = True

ex.ActiveSheet.Columns("A:A").ColumnWidth = 10

rsAsp.Open "SELECT * FROM Table1", conn
Dim i
i=3

While not rsAsp.EOF
  ex.ActiveSheet.Cells(i,1).Value = rsAsp.Fields(0)
  ex.ActiveSheet.Cells(i,2).Value = rsAsp.Fields(1)
  rsAsp.MoveNext 
Wend

ex.ActiveWorkbook.SaveAs Server.MapPath(".") & "\" & f
ex.Quit

Set rsAsp = Nothing
Set ex = Nothing
Set fs = Nothing
%>
<body onload="document.location.href='<% =f %>'">
</HTML>
<!--#include file = "../include/CloseConnection.asp"-->
			  

I used FileSystemObject to create temporary names for Excel files.

An advantage of this method is that Excel could be completely automated thru its objects.

But there are many drawbacks. First of all, read this page regarding the problems which can occur when Excel is installed on the server (needed for automation). Then, it must devise a solution to delete all those xls files created on the server. Also, is slow, because Excel is running in a separate process. And every time there is an error the page hangs up, because an message box will be issued on the server.

Let's see another solution, having Excel installed on the client computer (browser). However, on client side, Excel is needed, to view excel files, so we can use it to generate the file.

Here, will be facing other problems: how to pass parameters from ASP page to Excel files? And how can we safely access the datasource from the client computer?

Second problem could be solved using "MSDFMAP.Handler" or other solutions.

For first answer there is a solution for Internet Explorer, passing them by clipboard. Let's see the page which open the XLS file (report.asp):

<% Response.Expires =-2000 
On Error Resume Next
server_name="http://localhost"
%>
<HTML>
<HEAD>
<script language=JavaScript>
function start() {
	window.clipboardData.setData('Text','<% 
	select case Request.QueryString("xls")  'name of xls file
	case "EXCEL1"
		Response.Write Request.QueryString("xls") & "|" & _
		server_name & "|" & _
		Request.QueryString("Param1") & "|" & _
		Session("UserName") & "|" & _
		Session("Pass")

	End Select
		%>');
	location.href='<%= Request.QueryString("xls") %>.xls';
}
</script>
</HEAD>
<BODY onload="start()">
</BODY>
</HTML>
			  

Then, in Excel1.xls we could query all parameters passed from ASP (separated by "|") and built the Excel doc against those parameters. In this example I use information from a database. In Excel1.xls you have to add at References "MS Forms 2.0" (to access the clipboard) and ADO or RDS.

Sub Auto_Open()
On Error Resume Next

Application.ScreenUpdating = False

'get the params from clipboard
Dim s As String
Set MyData = New DataObject
MyData.GetFromClipboard
If MyData.GetFormat(1) Then
    s = MyData.GetText()
    MyData.SetText " ", 1
    MyData.PutInClipboard
End If

If Left$(s, 6) = "EXCEL1" Then  'security check
	'get params from s variable

	'open the database and build the xls doc

End If

Application.ScreenUpdating = True

End Sub 'Auto_Open
			  

As you can see, the xls file could be writen by code. When the file is re-open it won't be re-build because the parameters aren't in the clipboard (it's a good chance that Left$(s, 6) <> "EXCEL1").

The Excel doc could be build on the client-side in this way but still remains many problems. Every time a doc is open a security warning is issued because the doc is containing macros (Auto_Open()). Also, it could be security problems when accessing database remotely and ADO or RDS must be installed on client-computers.

A more reliable solution is by using external (commercial) components as ExcelWriter from SoftArtisans or ExcelSpeedGen. One word: it costs!

Also, there are some open-source projects for the same reason: to generate Excel docs. See www.sourceforge.net/projects/poi or jakarta.apache.org/poi/hssf/index.html (the same).

Of course, you've seen many articles(aCat,aTitle,aAuthor,aDate,aContent,aViewed) on the net to generate Excel documents using HTML, as samples from Microsoft:

Basicaly, any HTML file built like the one below is interpreted as Excel file, just to change the extension to *.xls (for instance excel2.xls):

<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="application/vnd.ms-excel">
</HEAD>
<BODY>
<TABLE cellspacing=1 cellpadding=1 border=1>
	<TR>
		<TD align=center colspan=4>
	    <FONT size=4 color=blue>Price Quote</FONT></TD>
	</TR>
	<TR>
		<TD><B>Product</B></TD>
		<TD><B>Price</B></TD>
		<TD><B>Quantity</B></TD>
		<TD><B>Total</B></TD>
	</TR>
	<TR>
		<TD>Widget A</TD>
		<TD>36</TD>
		<TD>2</TD>
		<TD>=B3*C3</TD>
	</TR>
	<TR>
		<TD>Widget B</TD>
		<TD>45</TD>
		<TD>3</TD>
		<TD>=B4*C4</TD>
	</TR>
	<TR>
		<TD></TD>
		<TD></TD>
		<TD><B>Total</B></TD>
		<TD>=Sum(D3:D4)</TD>
	</TR>

 </TABLE>
</BODY>
</HTML>
	

The key is HTTP-EQUIV="Content-Type" CONTENT="application/vnd.ms-excel" in <HEAD> part. This will be corectly interpreted if Excel is installed on client computer.

One major drawback is that it could be only one worksheet per document (not multiple-sheets). This solution works with both Excel 97, 2000 and 2002.

Starting with Excel 2000 (and Excel 2002) documents could be saved and loaded as XML files. Using this method you can build directly xls docs from xml files, having multiple sheets.

A good start is msdn.microsoft.com/library/en-us/dnexcl2k2/html/odc_xmlss.asp?frame=true where you can find XML spreadsheet tag hierarchy explained (or msdn.microsoft.com/library/en-us/dnexcl2k2/html/odc_xlsmlinss.asp?frame=true). Also you can see msdn.microsoft.com/library/en-us/dnexcl2k2/html/odc_xlflatnr.asp?frame=true and some practical solutions as the following:

The problem is that all these are working with Excel 2000 or 2002, and isn't working with previous versions of Excel (mainly Excel 97). If the user doesn't have these newer versions of Excel he can't view the docs.

To write XLS files directly, without MS Excel installed it could be another solution, too. For instance, it could be used Perl. There is an article describe this method here. Or you can see this solution using Perl. Another resources on the same theme could be found here (LAOLA). I haven't tried them and I haven't any clue how reliable they are.

And now, it's time to see a solution that could meet your needs, using ADO. You can read more about this solution at:

But I'll change it to use directly from a web browser (both IE & Netscape). The components used are ADO and FileSystemObject. The version of ADO must be at least 2.5 to use ADODB.Stream.

First of all, we create a folder with all Excel documents used as templates (here called "templates" in working folder). And we create a temporary folder in working folder, too (in this example called "tmp"). It could be used Windows temporary folder (usually c:\windows\temp), but to keep track of all created documents we used our temporary folder. In our example, the template for XLS doc is templates\products.xls.

Also, we have an Access database as the source of informations to be wrote in XLS documents (excel_db1.mdb)

Then try the code as bellow in products.asp:

<%
Response.Expires = -2000
Response.Buffer = TRUE

'--- Create temporary file
Dim path
path=Server.MapPath(".")

Dim fs, file
Set fs=Server.CreateObject("Scripting.FileSystemObject")
file = path & "\tmp\" & fs.GetTempName
fs.CopyFile path & "\templates\products.xls", file

'--- Modify Excel template
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
               "Data Source=" & file & _
               ";Extended Properties=""Excel 8.0;HDR=NO;"""

Dim oProdConn, oProdRS
Set oProdConn = Server.CreateObject("ADODB.Connection")
Set oProdRS =  Server.CreateObject("ADODB.Recordset")
oProdConn.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & _
                path & "\excel_db1.mdb"
                    
oProdRS.Open "SELECT * FROM Products", oProdConn
                   
Dim oRS 
Set oRS = Server.CreateObject("ADODB.Recordset")
oRS.Open "Select * from Items", oConn, 1, 3 
         '1=adOpenKeyset, 3=adLockOptimistic
    
Do Until oProdRS.EOF
    oRS.AddNew
    For i = 0 To 2
        oRS.Fields(i).Value = oProdRS.Fields(i).Value
    Next
    oRS.Update
    oProdRS.MoveNext
Loop
    
oProdRS.Close
Set oProdRS = Nothing
oProdConn.Close
Set oProdConn = Nothing
    
oConn.Close
Set oConn = Nothing

'--- Build the stream to client
Response.ContentType = "application/vnd.ms-excel"

Dim vntStream

Set oMyObject = Server.CreateObject("ADODB.Stream")
oMyObject.Type = 1 'adTypeBinary
oMyObject.Open
oMyObject.LoadFromFile file 
vntStream = oMyObject.Read

Response.BinaryWrite(vntStream)

'--- Delete tmp file & close all
oMyObject.Close
fs.DeleteFile file

Set oMyObject = Nothing
Set fs = Nothing

Response.End
%>
			  

The code is almost self-explanatory. Into the line:
oRS.Open "Select * from Items"

the table "Items" isn't a real table, but a named area in Excel file (Insert | Name | Define...), and then made hidden (line 2 isn't visible in XLS doc).

It's important to notice that MS Excel doesn't have to be installed on the server and all temporary files are deleted.

The user will get an Excel file to download, both in IE and NN.

You can download all this sample here (11 kb).

Last solution presented here, is to write directly Excel binary files (BIFF). The problem is that the format of Excel files aren't documented. All you coud find are some examples from Microsoft as:

Also, you can download MS Excel 97 SDK where is a useful program called BIFFVIEW.EXE, to see the internal structure of a binary Excel file. But more interesting could be this PDF document which contains part of Excel file format.

You can see an example of using this method, at work, in VB here. It could be opened with newer versions of Excel (backward compatibility is working).

A big drawback is that this format is used for Excel 2.1 and is just 1 sheet per doc. You can't create multi-sheets documents.

Other solution is to try Microsoft Office Web Components. You can read more here (an example).

Last thing I want to mention is MS Office Developer page from MSDN, where it could be interestin things regarding Excel programming.

Also, it could be another solutions for this problem. It's up to you to apply one of these solutions or any other you consider will suit you needs.

 

« Go back

Google

Web AdvanCode

All News

»TheBabelTower.org

CarsMarket.ca - Canada's Cars Marketplace - Easy Search. Sell for free.

  © 2002-2005 AdvanCode · Terms of use · Privacy Policy · Site Map