Question

I have the following problem:

I have a table with 5000 random generated demo data sets

enter image description here

I would now like to export this one line at a Xliff file.

So the end result should look like. Small example

<?xml version='1.0' encoding='utf-8'?>
<xliff version="1.1">
  <file original="source\simple.htm" source-language="EN" target-language="DE" datatype="html">
    <header>
      <skl>
        <external-file uid="017dbcf0-c82c-11e2-ba2b-005056c00008" href="skl\simple.htm.skl"/>
      </skl>
    </header>
    <body>
      <trans-unit id="00QlKZsL6GyW6B92Ev81Fb2HP3Z0ma">
        <source xml:lang="EN">2hH3khJvy1gmFNTLSB0Crka0A8TTKReuYxbV2hI9E8AjXwCV3F</source>
        <target xml:lang="DE">3ydQZWavaKvxrlbh1ewXZakLL00LEPG6zVTyty6fiLrPdx9UE4</target>
      <note/></trans-unit>
      <trans-unit id="016ynILnditynwtYwcl6vJPTLCzvo7">
        <source xml:lang="EN">dyC28VRCI9O37PTHENinp4sgMkr5R0HO1Yo53hUQKNr4GoLFG4</source>
        <target xml:lang="DE">sEkgstffmS4k5KB1JZkNSYbUnzzlFBNT30oYmtfId8dnspG3No</target>
      <note>Testnotiz</note></trans-unit>
      <trans-unit id="03YNBAZ1YWvkqaG4PRxKSiWENOCXuB">
        <source xml:lang="EN">BHpY8LDs8oJAr8I1EfZzeJX24GZ3TLIr9GUAYcnSPYHjDfKRqk</source>
        <target xml:lang="DE">7Rd7bW2lg2Uc4uStCoosZuNgOzA9qWN7OsvW2gBcHa3ctnmF3Q</target>
      <note/></trans-unit>
    </body>
  </file>
</xliff>

As a component of the Edit / Paste Xliff the file I wanted to grab my XMLDocument. I already had a few days ago wrote a demo program where I upload a file using XMLDocument and then Xliff purely write something again. So these routines at least for the targets I already have.

I feel now more that I still have no real idea how all the data from the MySQL table as the best piece of land in a Xliff file pack.

First thought was possible for me to go through the entire table line by line, then save it into an array and then write my loop over the array and in the file.

Would appreciate some other suggestions / concepts. Since it is a test of the speed of the XMLDocument component in the end I would concepts / ideas that lead to a rapid course prefer.

Was it helpful?

Solution

Here a solution using the Strategy Design Pattern to have an easy extendable solution for various export strategies (XML Plain or XmlDoc, CSV, ...)

Base Document

unit Document;

interface

type
  TDocument = class;

  IDocumentExportFileStrategy = interface
    ['{787B60E5-A3CA-485C-A46E-248A43D7175C}']
    procedure ExportDoc( AContext : TDocument; const AFileName : string );
  end;

  TDocument = class
  private
    FExportFileStrategy : IDocumentExportFileStrategy;
  protected
    function GetValue( const Name : string ) : Variant; virtual; abstract;
  public
    procedure First; virtual; abstract;
    procedure Next; virtual; abstract;
    function Eof : Boolean; virtual; abstract;

    property Value[const Name : string] : Variant read GetValue;

    property ExportFileStrategy : IDocumentExportFileStrategy read FExportFileStrategy write FExportFileStrategy;

    procedure ExportTo( const AFileName : string );
  end;

implementation

{ TDocument }

procedure TDocument.ExportTo( const AFileName : string );
begin
  FExportFileStrategy.ExportDoc( Self, AFileName );
end;

end.

An Xliff export strategy writing plain text for fast execution

unit XliffPlainExporter;

interface

uses
  Document,

  SysUtils, Variants,
  Classes;

type
  TXliffPlainExporter = class( TInterfacedObject, IDocumentExportFileStrategy )
  private
    procedure WriteLine( AStream : TStream; ALine : string );
  protected
    procedure WriteHead( AContext : TDocument; AStream : TStream );
    procedure WriteDetails( AContext : TDocument; AStream : TStream );
    procedure WriteFoot( AContext : TDocument; AStream : TStream );
  public
    procedure ExportDoc( AContext : TDocument; const AFileName : string );
  end;

implementation

{ TXliffPlainExporter }

procedure TXliffPlainExporter.ExportDoc( AContext : TDocument; const AFileName : string );
var
  LStream : TStream;
  LFileName : string;
begin
  AContext.First;
  if not AContext.Eof
  then
    begin

      LFileName := AFileName;
      if ExtractFileExt( LFileName ) = ''
      then
        LFileName := ChangeFileExt( LFileName, '.xml' );

      LStream := TFileStream.Create( LFileName, fmCreate );
      try
        WriteHead( AContext, LStream );
        WriteDetails( AContext, LStream );
        WriteFoot( AContext, LStream );
      finally
        LStream.Free;
      end;

    end;
end;

procedure TXliffPlainExporter.WriteHead( AContext : TDocument; AStream : TStream );
begin
  WriteLine( AStream, '<?xml version=''1.0'' encoding=''utf-8''?>' );
  WriteLine( AStream, '<xliff version="1.1">' );
  WriteLine( AStream, ' <file original="source\simple.htm" source-language="EN" target-language="DE" datatype="html">' );
  WriteLine( AStream, ' <header>' );
  WriteLine( AStream, ' <skl>' );
  WriteLine( AStream, ' <external-file uid="017dbcf0-c82c-11e2-ba2b-005056c00008" href="skl\simple.htm.skl"/>' );
  WriteLine( AStream, ' </skl>' );
  WriteLine( AStream, ' </header>' );
  WriteLine( AStream, ' <body>' );
end;

procedure TXliffPlainExporter.WriteDetails( AContext : TDocument; AStream : TStream );
begin
  while not AContext.Eof do
    begin
      WriteLine( AStream, Format( ' <trans-unit id="%s">', [VarToStr( AContext.Value['id'] )] ) );
      WriteLine( AStream, Format( ' <source xml:lang="EN">%s</source>', [VarToStr( AContext.Value['src'] )] ) );
      WriteLine( AStream, Format( ' <target xml:lang="DE">%s</target>', [VarToStr( AContext.Value['dst'] )] ) );
      WriteLine( AStream, ' <note/></trans-unit>' );

      AContext.Next;
    end;
end;

procedure TXliffPlainExporter.WriteFoot( AContext : TDocument; AStream : TStream );
begin
  WriteLine( AStream, ' </body>' );
  WriteLine( AStream, ' </file>' );
  WriteLine( AStream, '</xliff>' );
end;

procedure TXliffPlainExporter.WriteLine( AStream : TStream; ALine : string );
var
  LLine : TStream;
begin
  LLine := TStringStream.Create( ALine + sLineBreak, TEncoding.UTF8 );
  try
    LLine.Position := 0;
    AStream.CopyFrom( LLine, LLine.Size );
  finally
    LLine.Free;
  end;
end;

end.

Simple Test-Document just for testing purpose

unit TestDocument;

interface

uses
  Document;

type
  TTestDocument = class( TDocument )
  private
    FIndex : Integer;
  protected
    function GetValue( const Name : string ) : Variant; override;
  public
    function Eof : Boolean; override;
    procedure First; override;
    procedure Next; override;
  end;

implementation

uses
  SysUtils,
  StrUtils;

{ TTestDocument }

function TTestDocument.Eof : Boolean;
begin
  Result := FIndex >= 100;
end;

procedure TTestDocument.First;
begin
  inherited;
  FIndex := 0;
end;

function TTestDocument.GetValue( const Name : string ) : Variant;
begin
  case IndexText( Name, ['id', 'src', 'dst'] ) of
    0 :
      Result := Format( 'id%8.8d', [FIndex + 1] );
    1 :
      Result := Format( 'src%8.8d', [FIndex + 1] );
    2 :
      Result := Format( 'dst%8.8d', [FIndex + 1] );
  end;
end;

procedure TTestDocument.Next;
begin
  inherited;
  Inc( FIndex );
end;

end.

And putting the pieces together

program DataExportStrategy;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  Document in 'Document.pas',
  TestDocument in 'TestDocument.pas',
  XliffPlainExporter in 'XliffPlainExporter.pas';

procedure Test;
var
  LDoc : TDocument;
begin
  LDoc := TTestDocument.Create;
  try
    LDoc.ExportFileStrategy := TXliffPlainExporter.Create;
    LDoc.ExportTo( 'test' );
  finally
    LDoc.Free;
  end;

  WriteLn( 'Export finished' );
end;

begin
  try

    Test;

  except
    on E : Exception do
      WriteLn( E.ClassName, ': ', E.Message );
  end;

  ReadLn;

end.

In your case, you would like to have a document based on a DataSet so you implement a TDataSetDocument

unit DataSetDocument;

interface

uses
  Document,
  Data.DB;

type
  TDataSetDocument = class( TDocument )
  private
    FDataSet : TDataSet;
  protected
    function GetValue( const Name : string ) : Variant; override;
  public
    constructor Create( ADataSet : TDataSet );

    function Eof : Boolean; override;
    procedure Next; override;
    procedure First; override;
  end;

implementation

{ TDataSetDocument }

constructor TDataSetDocument.Create( ADataSet : TDataSet );
begin
  inherited Create;
  FDataSet := ADataSet;
end;

function TDataSetDocument.Eof : Boolean;
begin
  Result := FDataSet.Eof;
end;

procedure TDataSetDocument.First;
begin
  inherited;
  FDataSet.First;
end;

function TDataSetDocument.GetValue( const Name : string ) : Variant;
begin
  Result := FDataSet.FieldByName( Name ).Value;
end;

procedure TDataSetDocument.Next;
begin
  inherited;
  FDataSet.Next;
end;

end.

and use it

var
  LDoc : TDocument;

LDoc := TDataSetDocument.Create( MyQuery );
try
  LDoc.ExportStrategy := TXliffPlainExporter.Create;
  LDoc.ExportTo( 'test' );
finally
  LDoc.Free;
end;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top