Search code examples
mysqldelphitranslationxliff

Fetch records from table and save to file


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.


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;