{ fpsopendocument.pas Writes an OpenDocument 1.0 Spreadsheet document An OpenDocument document is a compressed ZIP file with the following files inside: content.xml - Actual contents meta.xml - Authoring data settings.xml - User persistent viewing information, such as zoom, cursor position, etc. styles.xml - Styles, which are the only way to do formatting mimetype - application/vnd.oasis.opendocument.spreadsheet META-INF manifest.xml - Specifications obtained from: http://docs.oasis-open.org/office/v1.1/OS/OpenDocument-v1.1.pdf AUTHORS: Felipe Monteiro de Carvalho } unit fpsopendocument; {$ifdef fpc} {$mode delphi} {$endif} interface uses Classes, SysUtils, zipper, fpspreadsheet; type { TsSpreadOpenDocWriter } TsSpreadOpenDocWriter = class(TsCustomSpreadWriter) protected FZip: TZipper; // Strings with the contents of files // filename\ FMeta, FSettings, FStyles: string; FContent: string; FMimetype: string; // filename\META-INF FMetaInfManifest: string; // Routines to write those files procedure WriteGlobalFiles; procedure WriteContent(AData: TsWorkbook); procedure WriteWorksheet(CurSheet: TsWorksheet); 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 WriteFormula(AStream: TStream; const ARow, ACol: Word; const AFormula: TRPNFormula); override; 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 { OpenDocument general XML constants } XML_HEADER = ''; { OpenDocument Directory structure constants } OOXML_PATH_CONTENT = 'content.xml'; OOXML_PATH_META = 'meta.xml'; OOXML_PATH_SETTINGS = 'settings.xml'; OOXML_PATH_STYLES = 'styles.xml'; OOXML_PATH_MIMETYPE = 'mimetype.xml'; OPENDOC_PATH_METAINF = 'META-INF\'; OPENDOC_PATH_METAINF_MANIFEST = 'META-INF\manifest.xml'; { OpenDocument schemas constants } SCHEMAS_XMLNS_OFFICE = 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'; SCHEMAS_XMLNS_DCTERMS = 'http://purl.org/dc/terms/'; SCHEMAS_XMLNS_META = 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'; SCHEMAS_XMLNS = 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties'; SCHEMAS_XMLNS_CONFIG = 'urn:oasis:names:tc:opendocument:xmlns:config:1.0'; SCHEMAS_XMLNS_OOO = 'http://openoffice.org/2004/office'; SCHEMAS_XMLNS_MANIFEST = 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'; SCHEMAS_XMLNS_FO = 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'; SCHEMAS_XMLNS_STYLE = 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'; SCHEMAS_XMLNS_SVG = 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'; SCHEMAS_XMLNS_TABLE = 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'; SCHEMAS_XMLNS_TEXT = 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'; SCHEMAS_XMLNS_V = 'urn:schemas-microsoft-com:vml'; SCHEMAS_XMLNS_NUMBER = 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'; SCHEMAS_XMLNS_CHART = 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'; SCHEMAS_XMLNS_DR3D = 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'; SCHEMAS_XMLNS_MATH = 'http://www.w3.org/1998/Math/MathML'; SCHEMAS_XMLNS_FORM = 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'; SCHEMAS_XMLNS_SCRIPT = 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'; SCHEMAS_XMLNS_OOOW = 'http://openoffice.org/2004/writer'; SCHEMAS_XMLNS_OOOC = 'http://openoffice.org/2004/calc'; SCHEMAS_XMLNS_DOM = 'http://www.w3.org/2001/xml-events'; SCHEMAS_XMLNS_XFORMS = 'http://www.w3.org/2002/xforms'; SCHEMAS_XMLNS_XSD = 'http://www.w3.org/2001/XMLSchema'; SCHEMAS_XMLNS_XSI = 'http://www.w3.org/2001/XMLSchema-instance'; { TsSpreadOpenDocWriter } procedure TsSpreadOpenDocWriter.WriteGlobalFiles; begin FMimetype := 'application/vnd.oasis.opendocument.spreadsheet'; FMetaInfManifest := XML_HEADER + LineEnding + '' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ''; FMeta := XML_HEADER + LineEnding + '' + LineEnding + ' ' + LineEnding + ' FPSpreadsheet Library' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ''; FSettings := XML_HEADER + LineEnding + '' + LineEnding + '' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' Tabelle1' + LineEnding + ' 100' + LineEnding + ' 100' + LineEnding + ' false' + LineEnding + ' true' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' 3' + LineEnding + ' 2' + 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 + ''; end; procedure TsSpreadOpenDocWriter.WriteContent(AData: TsWorkbook); var i: Integer; begin FContent := XML_HEADER + LineEnding + '' + LineEnding + ' ' + LineEnding + // Fonts ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + // Automatic styles ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + // Body ' ' + LineEnding + ' ' + LineEnding; for i := 0 to AData.GetWorksheetCount - 1 do begin WriteWorksheet(Adata.GetWorksheetByIndex(i)); end; FContent := FContent + ' ' + LineEnding + ' ' + LineEnding + ''; end; procedure TsSpreadOpenDocWriter.WriteWorksheet(CurSheet: TsWorksheet); var j, k: Integer; CurCell: PCell; begin // Header FContent := FContent + ' ' + LineEnding + ' ' + LineEnding; // The cells need to be written in order, row by row for j := 0 to CurSheet.GetLastRowNumber do begin FContent := FContent + ' ' + LineEnding; for k := 0 to CurSheet.FCells.Count - 1 do begin CurCell := CurSheet.FCells.Items[k]; if CurCell^.Row = j then WriteCellCallback(CurCell, nil); end; FContent := FContent + ' ' + LineEnding; end; // Footer FContent := FContent + ' ' + LineEnding; end; {******************************************************************* * TsSpreadOOXMLWriter.WriteStringToFile () * * DESCRIPTION: Writes a string to a file. Helper convenience method. * *******************************************************************} procedure TsSpreadOpenDocWriter.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 TsSpreadOpenDocWriter.WriteToFile(AFileName: string; AData: TsWorkbook); var TempDir: string; begin {FZip := TZipper.Create; FZip.ZipFiles(AFileName, x); FZip.Free;} // WriteToStream(nil, AData); WriteGlobalFiles(); WriteContent(AData); TempDir := IncludeTrailingBackslash(AFileName); { files on the root path } ForceDirectories(TempDir); WriteStringToFile(TempDir + OOXML_PATH_CONTENT, FContent); WriteStringToFile(TempDir + OOXML_PATH_META, FMeta); WriteStringToFile(TempDir + OOXML_PATH_SETTINGS, FSettings); WriteStringToFile(TempDir + OOXML_PATH_STYLES, FStyles); WriteStringToFile(TempDir + OOXML_PATH_MIMETYPE, FMimetype); { META-INF directory } ForceDirectories(TempDir + OPENDOC_PATH_METAINF); WriteStringToFile(TempDir + OPENDOC_PATH_METAINF_MANIFEST, FMetaInfManifest); 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 TsSpreadOpenDocWriter.WriteToStream(AStream: TStream; AData: TsWorkbook); begin end; procedure TsSpreadOpenDocWriter.WriteFormula(AStream: TStream; const ARow, ACol: Word; const AFormula: TRPNFormula); begin end; procedure TsSpreadOpenDocWriter.WriteLabel(AStream: TStream; const ARow, ACol: Word; const AValue: string); begin end; procedure TsSpreadOpenDocWriter.WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double); begin // The row should already be the correct one FContent := FContent + ' ' + LineEnding + ' 1' + LineEnding + ' ' + LineEnding; end; {******************************************************************* * Initialization section * * Registers this reader / writer on fpSpreadsheet * *******************************************************************} initialization RegisterSpreadFormat(TsCustomSpreadReader, TsSpreadOpenDocWriter, sfOpenDocument); end.