{ xlsxooxml.pas Writes an OOXML (Office Open XML) document An OOXML document is a compressed ZIP file with the following files inside: [Content_Types].xml _rels\.rels xl\_rels\workbook.xml.rels xl\workbook.xml xl\styles.xml xl\sharedStrings.xml xl\worksheets\sheet1.xml ... xl\worksheets\sheetN.xml Specifications obtained from: http://openxmldeveloper.org/default.aspx AUTHORS: Felipe Monteiro de Carvalho IMPORTANT: This writer doesn't work yet!!! This is just initial code. } unit xlsxooxml; {$ifdef fpc} {$mode delphi} {$endif} interface uses Classes, SysUtils, {zipper,} fpspreadsheet; type { TsSpreadOOXMLWriter } TsSpreadOOXMLWriter = class(TsCustomSpreadWriter) protected // FZip: TZipper; FContentTypes: string; FRelsRels: string; FWorkbook, FWorkbookRels, FStyles, FSharedString, FSheet1: string; public { General writing methods } procedure WriteStringToFile(AFileName, AString: string); procedure WriteToFile(AFileName: string; AData: TsWorkbook); override; procedure WriteToStream(AStream: TStream; AData: TsWorkbook); override; { Record writing methods } procedure WriteLabel(AStream: TStream; const ARow, ACol: Word; const AValue: string); override; procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double); override; end; implementation const { OOXML general XML constants } XML_HEADER = ''; { OOXML Directory structure constants } OOXML_PATH_TYPES = '[Content_Types].xml'; OOXML_PATH_RELS = '_rels\'; OOXML_PATH_RELS_RELS = '_rels\.rels'; OOXML_PATH_XL = 'xl\'; OOXML_PATH_XL_RELS = 'xl\_rels\'; OOXML_PATH_XL_RELS_RELS = 'xl\_rels\workbook.xml.rels'; OOXML_PATH_XL_WORKBOOK = 'xl\workbook.xml'; OOXML_PATH_XL_STYLES = 'xl\styles.xml'; OOXML_PATH_XL_STRINGS = 'xl\sharedStrings.xml'; OOXML_PATH_XL_WORKSHEETS = 'xl\worksheets\'; { OOXML schemas constants } SCHEMAS_TYPES = 'http://schemas.openxmlformats.org/package/2006/content-types'; SCHEMAS_RELS = 'http://schemas.openxmlformats.org/package/2006/relationships'; SCHEMAS_DOC_RELS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'; SCHEMAS_DOCUMENT = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument'; SCHEMAS_WORKSHEET = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet'; SCHEMAS_STYLES = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles'; SCHEMAS_STRINGS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings'; SCHEMAS_SPREADML = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'; { OOXML mime types constants } MIME_XML = 'application/xml'; MIME_RELS = 'application/vnd.openxmlformats-package.relationships+xml'; MIME_SPREADML = 'application/vnd.openxmlformats-officedocument.spreadsheetml'; MIME_SHEET = MIME_SPREADML + '.sheet.main+xml'; MIME_WORKSHEET = MIME_SPREADML + '.worksheet+xml'; MIME_STYLES = MIME_SPREADML + '.styles+xml'; MIME_STRINGS = MIME_SPREADML + '.sharedStrings+xml'; { TsSpreadOOXMLWriter } {******************************************************************* * TsSpreadOOXMLWriter.WriteStringToFile () * * DESCRIPTION: Writes a string to a file. Helper convenience method. * *******************************************************************} procedure TsSpreadOOXMLWriter.WriteStringToFile(AFileName, AString: string); var TheStream : TFileStream; S : String; begin TheStream := TFileStream.Create(AFileName, fmCreate); S:=AString; TheStream.WriteBuffer(Pointer(S)^,Length(S)); TheStream.Free; end; {******************************************************************* * TsSpreadOOXMLWriter.WriteToFile () * * DESCRIPTION: Writes an OOXML document to the disc * *******************************************************************} procedure TsSpreadOOXMLWriter.WriteToFile(AFileName: string; AData: TsWorkbook); var TempDir: string; begin {FZip := TZipper.Create; FZip.ZipFiles(AFileName, x); FZip.Free;} WriteToStream(nil, AData); TempDir := IncludeTrailingBackslash(AFileName); { files on the root path } ForceDirectories(TempDir); WriteStringToFile(TempDir + OOXML_PATH_TYPES, FContentTypes); { _rels directory } ForceDirectories(TempDir + OOXML_PATH_RELS); WriteStringToFile(TempDir + OOXML_PATH_RELS_RELS, FRelsRels); { xl directory } ForceDirectories(TempDir + OOXML_PATH_XL_RELS); WriteStringToFile(TempDir + OOXML_PATH_XL_RELS_RELS, FWorkbookRels); WriteStringToFile(TempDir + OOXML_PATH_XL_WORKBOOK, FWorkbook); WriteStringToFile(TempDir + OOXML_PATH_XL_STYLES, FStyles); WriteStringToFile(TempDir + OOXML_PATH_XL_STRINGS, FSharedString); { xl\worksheets directory } ForceDirectories(TempDir + OOXML_PATH_XL_WORKSHEETS); WriteStringToFile(TempDir + OOXML_PATH_XL_WORKSHEETS + 'sheet1.xml', FSheet1); end; {******************************************************************* * TsSpreadOOXMLWriter.WriteToStream () * * DESCRIPTION: Writes an Excel 2 file to a stream * * Excel 2.x files support only one Worksheet per Workbook, * so only the first will be written. * *******************************************************************} procedure TsSpreadOOXMLWriter.WriteToStream(AStream: TStream; AData: TsWorkbook); begin // WriteCellsToStream(AStream, AData.GetFirstWorksheet.FCells); FContentTypes := XML_HEADER + LineEnding + '' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ''; FRelsRels := XML_HEADER + LineEnding + '' + LineEnding + '' + LineEnding + ''; FWorkbookRels := XML_HEADER + LineEnding + '' + LineEnding + '' + LineEnding + '' + LineEnding + '' + LineEnding + ''; FWorkbook := XML_HEADER + LineEnding + '' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ''; FStyles := XML_HEADER + LineEnding + '' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ''; FSharedString := XML_HEADER + LineEnding + '' + LineEnding + ' ' + LineEnding + ' First' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' Second' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' Third' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' Fourth' + LineEnding + ' ' + LineEnding + ''; FSheet1 := XML_HEADER + LineEnding + '' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' 1' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' 2' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' 3' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' 4' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' 0' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' 1' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' 2' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' 3' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ''; end; {******************************************************************* * TsSpreadOOXMLWriter.WriteLabel () * * DESCRIPTION: Writes an Excel 2 LABEL record * * Writes a string to the sheet * *******************************************************************} procedure TsSpreadOOXMLWriter.WriteLabel(AStream: TStream; const ARow, ACol: Word; const AValue: string); var L: Byte; begin L := Length(AValue); { BIFF Record header } // AStream.WriteWord(WordToLE(INT_EXCEL_ID_LABEL)); // AStream.WriteWord(WordToLE(8 + L)); { BIFF Record data } // AStream.WriteWord(WordToLE(ARow)); // AStream.WriteWord(WordToLE(ACol)); { BIFF2 Attributes } AStream.WriteByte($0); AStream.WriteByte($0); AStream.WriteByte($0); { String with 8-bit size } AStream.WriteByte(L); AStream.WriteBuffer(AValue[1], L); end; {******************************************************************* * TsSpreadOOXMLWriter.WriteNumber () * * DESCRIPTION: Writes an Excel 2 NUMBER record * * Writes a number (64-bit IEE 754 floating point) to the sheet * *******************************************************************} procedure TsSpreadOOXMLWriter.WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double); begin { BIFF Record header } // AStream.WriteWord(WordToLE(INT_EXCEL_ID_NUMBER)); // AStream.WriteWord(WordToLE(15)); { BIFF Record data } // AStream.WriteWord(WordToLE(ARow)); // AStream.WriteWord(WordToLE(ACol)); { BIFF2 Attributes } AStream.WriteByte($0); AStream.WriteByte($0); AStream.WriteByte($0); { IEE 754 floating-point value } AStream.WriteBuffer(AValue, 8); end; {******************************************************************* * Initialization section * * Registers this reader / writer on fpSpreadsheet * *******************************************************************} initialization RegisterSpreadFormat(TsCustomSpreadReader, TsSpreadOOXMLWriter, sfOOXML); end.