mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-14 11:49:18 +02:00
* Changed CSV export to use CSVBuilder to be more RFC 4180 compliant
git-svn-id: trunk@30418 -
This commit is contained in:
parent
6b130438eb
commit
a4ddc64e78
@ -5,7 +5,7 @@ unit fpcsvexport;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, DB, fpDBExport;
|
||||
Classes, SysUtils, fpDBExport, csvreadwrite;
|
||||
|
||||
Type
|
||||
{ TCSVFormatSettings }
|
||||
@ -14,35 +14,40 @@ Type
|
||||
Private
|
||||
FDelimiter: String;
|
||||
FHeaderRow: Boolean;
|
||||
FQuoteStrings: TQuoteStrings;
|
||||
FIgnoreOuterWhiteSpace: Boolean;
|
||||
FRowDelimiter: String;
|
||||
FStringQuoteChar: String;
|
||||
FQuoteChar: Char;
|
||||
Public
|
||||
Constructor Create(DoInitSettings : Boolean); override;
|
||||
Procedure Assign(Source : TPersistent); override;
|
||||
// Kept for compatibility with older versions; please replace with QuoteChar
|
||||
Property StringQuoteChar : Char Read FQuoteChar Write FQuoteChar; deprecated 'Please replace with QuoteChar';
|
||||
Published
|
||||
// Properties
|
||||
// Delimiter between fields/columns. Traditionally , for CSV.
|
||||
Property FieldDelimiter : String Read FDelimiter Write FDelimiter;
|
||||
//If no, CSV is RFC 4180 compliant; if yes, it matches the unofficial Creativyst specification
|
||||
Property IgnoreOuterWhitespace : Boolean Read FIgnoreOuterWhiteSpace write FIgnoreOuterWhiteSpace;
|
||||
// Line ending to be used between rows of data (e.g. #13#10 for standard CSV)
|
||||
Property RowDelimiter : String Read FRowDelimiter Write FRowDelimiter;
|
||||
// Whether or not the file should have a header row with field names
|
||||
Property HeaderRow : Boolean Read FHeaderRow Write FHeaderRow default true;
|
||||
Property QuoteStrings : TQuoteStrings Read FQuoteStrings Write FQuoteStrings;
|
||||
Property StringQuoteChar : String Read FStringQuoteChar Write FStringQuoteChar;
|
||||
// If fields need to be surrounded by quotes, use this character (e.g. ")
|
||||
Property QuoteChar : Char Read FQuoteChar Write FQuoteChar;
|
||||
end;
|
||||
|
||||
{ TCustomCSVExporter }
|
||||
|
||||
TCustomCSVExporter = Class(TCustomFileExporter)
|
||||
private
|
||||
FCurrentRow:String;
|
||||
FCSVOut: TCSVBuilder;
|
||||
function GetCSVFormatsettings: TCSVFormatSettings;
|
||||
procedure OutputRow(const ARow: String);
|
||||
procedure SetCSVFormatSettings(const AValue: TCSVFormatSettings);
|
||||
Protected
|
||||
Function CreateFormatSettings : TCustomExportFormatSettings; override;
|
||||
Procedure DoBeforeExecute; override;
|
||||
Procedure DoAfterExecute; override;
|
||||
Procedure DoDataHeader; override;
|
||||
Procedure DoDataRowStart; override;
|
||||
Procedure ExportField(EF : TExportFieldItem); override;
|
||||
Procedure DoDataRowEnd; override;
|
||||
Public
|
||||
@ -82,27 +87,23 @@ implementation
|
||||
procedure TCustomCSVExporter.DoBeforeExecute;
|
||||
begin
|
||||
inherited DoBeforeExecute;
|
||||
FCSVOut:=TCSVBuilder.Create;
|
||||
if (FormatSettings.FieldDelimiter<>'') then
|
||||
FCSVOut.Delimiter:=FormatSettings.FieldDelimiter[1];
|
||||
FCSVOut.IgnoreOuterWhitespace:=FormatSettings.IgnoreOuterWhitespace;
|
||||
FCSVOut.LineEnding:=FormatSettings.RowDelimiter;
|
||||
FCSVOut.QuoteChar:=FormatSettings.QuoteChar;
|
||||
OpenTextFile;
|
||||
FCSVOut.SetOutput(Stream); //output to the export stream
|
||||
end;
|
||||
|
||||
procedure TCustomCSVExporter.DoAfterExecute;
|
||||
begin
|
||||
FCSVOut.Free;
|
||||
CloseTextFile;
|
||||
inherited DoAfterExecute;
|
||||
end;
|
||||
|
||||
procedure TCustomCSVExporter.OutputRow(Const ARow : String);
|
||||
|
||||
Var
|
||||
RD : String;
|
||||
|
||||
begin
|
||||
RD:=FormatSettings.RowDelimiter;
|
||||
If (RD='') then
|
||||
Writeln(TextFile,ARow)
|
||||
else
|
||||
Write(TextFile,ARow,RD)
|
||||
end;
|
||||
|
||||
function TCustomCSVExporter.GetCSVFormatsettings: TCSVFormatSettings;
|
||||
begin
|
||||
@ -124,84 +125,29 @@ end;
|
||||
procedure TCustomCSVExporter.DoDataHeader;
|
||||
|
||||
Var
|
||||
S : String;
|
||||
I : Integer;
|
||||
|
||||
begin
|
||||
If FormatSettings.HeaderRow then
|
||||
begin
|
||||
S:='';
|
||||
For I:=0 to ExportFields.Count-1 do
|
||||
begin
|
||||
If (S<>'') then
|
||||
S:=S+FormatSettings.FieldDelimiter;
|
||||
S:=S+ExportFields[i].ExportedName;
|
||||
FCSVOut.AppendCell(ExportFields[i].ExportedName);
|
||||
end;
|
||||
OutputRow(S);
|
||||
FCSVOut.AppendRow; //close off with line ending
|
||||
end;
|
||||
inherited DoDataHeader;
|
||||
end;
|
||||
|
||||
|
||||
procedure TCustomCSVExporter.DoDataRowStart;
|
||||
begin
|
||||
FCurrentRow:='';
|
||||
end;
|
||||
|
||||
procedure TCustomCSVExporter.ExportField(EF: TExportFieldItem);
|
||||
|
||||
Function HaveSpace(Const S : String;QS : TQuoteStrings) : Boolean;
|
||||
|
||||
begin
|
||||
Result:=(qsSpace in QS) and (Pos(' ',S)<>0)
|
||||
end;
|
||||
|
||||
Function HaveDelimiter(Const S : String;QS : TQuoteStrings) : Boolean;
|
||||
|
||||
Var
|
||||
FD : String;
|
||||
|
||||
begin
|
||||
Result:=(qsDelimiter in QS);
|
||||
If Result then
|
||||
begin
|
||||
FD:=FormatSettings.FieldDelimiter;
|
||||
Result:=(FD<>'') and (Pos(FD,S)<>0);
|
||||
end;
|
||||
end;
|
||||
|
||||
Var
|
||||
S,C : String;
|
||||
QS : TQuoteStrings;
|
||||
|
||||
begin
|
||||
S:=FormatField(EF.Field);
|
||||
QS:=FormatSettings.QuoteStrings;
|
||||
{If specified, quote everything that can contain delimiters;
|
||||
leave numeric, date fields alone:}
|
||||
If (
|
||||
(EF.Field.DataType in StringFieldTypes) or
|
||||
(EF.Field.DataType in MemoFieldTypes) or
|
||||
(EF.Field.DataType in BlobFieldTypes)
|
||||
)
|
||||
and (QS<>[]) then
|
||||
begin
|
||||
If (qsAlways in QS) or HaveSpace(S,QS) or HaveDelimiter(S,QS) then
|
||||
begin
|
||||
C:=FormatSettings.StringQuoteChar;
|
||||
S:=C+S+C;
|
||||
end;
|
||||
end;
|
||||
If (FCurrentRow<>'') then
|
||||
FCurrentRow:=FCurrentRow+FormatSettings.FieldDelimiter;
|
||||
FCurrentRow:=FCurrentRow+S;
|
||||
FCSVOut.AppendCell(FormatField(EF.Field));
|
||||
end;
|
||||
|
||||
|
||||
procedure TCustomCSVExporter.DoDataRowEnd;
|
||||
begin
|
||||
OutputRow(FCurrentRow);
|
||||
FCurrentRow:='';
|
||||
FCSVOut.AppendRow; //Line ending
|
||||
end;
|
||||
|
||||
constructor TCustomCSVExporter.Create(Aowner: TComponent);
|
||||
@ -213,14 +159,12 @@ end;
|
||||
|
||||
constructor TCSVFormatSettings.Create(DoInitSettings: Boolean);
|
||||
begin
|
||||
// These defaults are meant to be Excel CSV compatible
|
||||
inherited Create(DoInitSettings);
|
||||
FHeaderRow:=True;
|
||||
FDelimiter:=',';
|
||||
FStringQuoteChar:='"';
|
||||
FQuoteStrings:=[qsSpace, qsDelimiter];
|
||||
{Sensible defaults as reading unquoted strings with delimiters/spaces will
|
||||
either fail by creating phantom fields (qsDelimiter) or delete leading or
|
||||
trailing data/spaces (qsSpace)}
|
||||
FQuoteChar:='"';
|
||||
FRowDelimiter:=LineEnding;
|
||||
end;
|
||||
|
||||
procedure TCSVFormatSettings.Assign(Source: TPersistent);
|
||||
@ -233,10 +177,9 @@ begin
|
||||
begin
|
||||
FS:=Source as TCSVFormatSettings;
|
||||
FDelimiter:=FS.FDelimiter;
|
||||
FHeaderRow:=FS.FHEaderRow;
|
||||
FQuoteStrings:=FS.FQuoteStrings;
|
||||
FHeaderRow:=FS.FHeaderRow;
|
||||
FRowDelimiter:=FS.FRowDelimiter;
|
||||
FStringQuoteChar:=FS.FStringQuoteChar;
|
||||
FQuoteChar:=FS.FQuoteChar;
|
||||
end;
|
||||
inherited Assign(Source);
|
||||
end;
|
||||
@ -250,8 +193,8 @@ end;
|
||||
Procedure UnRegisterCSVExportFormat;
|
||||
|
||||
begin
|
||||
ExportFormats.UnRegisterExportFormat(SCSVExport);
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
||||
|
@ -517,7 +517,6 @@ begin
|
||||
ExportSettings:=TCSVFormatSettings.Create(true);
|
||||
try
|
||||
ExportSettings.FieldDelimiter:=';';
|
||||
ExportSettings.QuoteStrings:=[qsAlways,qsSpace,qsDelimiter]; //quote everything we can
|
||||
ExportSettings.StringQuoteChar:='"'; //try explicit assignment
|
||||
ExportSettings.RowDelimiter:=#10; //Unix/Linux format
|
||||
ExportSettings.BooleanFalse:='onwaar'; //why not a Dutch output format?
|
||||
|
Loading…
Reference in New Issue
Block a user