Link to home
Start Free TrialLog in
Avatar of BdLm
BdLmFlag for Germany

asked on

Rave Reports : Print Table + 1 Recorde one Page

I have a TTable with 2 Strings , 2 XML Memo Fields  and 2 Image Fields.

 * new to create a report (with RAVE)
 * one record one page
 * must read and extract data from the XML, need a lot of code to to that

a)
found   https://www.experts-exchange.com/questions/23374082/Delphi-Rave-Reports.html?sfQueryTermInfo=1+10+30+delphi+rave 

but not sure : how to loop through the table

b) is RAVE a good choice ??

c) a I need to extract an calculate data from the XML , I feel  I need a code based report
Avatar of developmentguru
developmentguru
Flag of United States of America image

Personally I love using Rave reports.  It can take a little while to get used to some of it's quirks (like it does with ALL reporting software), but it is worth it.  Now, I would handle this request in two parts...

1) Read the data in as usual and parse each record to extract the XML you need.  I do not know how many fields / totals / etc you may need from this, more info would help.  I would have a TClientDataset or a temp table set up to handle the data as you generate it.  This will allow you to provide Rave with fields to work with instead of sub-datasets within other fields.  This portion is the code based approach you mentioned you thought you would need.

2) With step 1 done, all the data is ready for Rave to process in an easy, RAD, way.

Have fun :-)

(If you need more help, I would need more specifics on EXACTLY what types of data you are processing.  Example data would also help)
Avatar of Ephraim Wangoya

I on the other hand have never been a fun of Rave Reports, just wait until you want to create a multi-threaded application producing reports, You will get what I mean.

I prefer Quick Reports to Rave but thats just me

For the XML fields, you can just pre-calculate what you need and transform the data to a different dataset which you will actually use for the report
Avatar of BdLm

ASKER

would like to get here a code skelleton with the basic functions ... ideas to make a code based report like the demo page
paint--RAVE--REPORT.bmp
Still no example data?!?
Avatar of BdLm

ASKER

yes,  will accept a basic code sample as an answer  - should be really a code based report
Avatar of BdLm

ASKER

@ developmentguru


can you do code based rave report for the borland sample database biolife.db //  fishfacts project.

I complete do not understand how to work with dbbands ...  from code based approach
Avatar of BdLm

ASKER

here come the skeleton i made for  evaluation
unit Unit_LibraryReportTool;
{ *****************************************************************************
  *
  *
  *       DEMO  DUMP the Content of the Borland biolife.db with RAVE reports
  *
  *****************************************************************************}

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, StdCtrls,  DB, Grids,
  DBGrids, DBTables, ComCtrls, ExtCtrls,

  //  RAVE
  RpRave, RpDefine, RpCon, RpConDS,


  RpBase, RpSystem, RpConBDE ;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Exit1: TMenuItem;
    ReportTable: TTable;
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
    LoadLibararyDB1: TMenuItem;
    MainStatusBar: TStatusBar;
    Report1: TMenuItem;
    StartReport1: TMenuItem;
    Panel1: TPanel;
    Label1: TLabel;
    ListBox1: TListBox;
    RvTableConnection1: TRvTableConnection;
    LibRvSystem: TRvSystem;
    procedure Exit1Click(Sender: TObject);
    procedure LoadLibararyDB1Click(Sender: TObject);
    procedure StartReport1Click(Sender: TObject);
    procedure LibRvSystemPrint(Sender: TObject);
  private
    { Private-Deklarationen }
    FLibraryFilename   :  String;     ///  the name of the table for report
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Exit1Click(Sender: TObject);
begin
      close;
end;

procedure TForm1.LoadLibararyDB1Click(Sender: TObject);
begin
      FLibraryFilename := 'e:\biolife.db';

      ReportTable.Active := false;

      ReportTable.TableName := FLibraryFilename;

      ReportTable.Active := true;


end;

///
///
///
procedure TForm1.LibRvSystemPrint(Sender: TObject);
begin
      with Sender as TBaseReport do
        begin

        SetFont('ARIAL',15);
        GoToXY(1,1);
        Print ('Welcome to the rave demo report project !!');

        end;
end;

procedure TForm1.StartReport1Click(Sender: TObject);
begin
      ////

      MainStatusBar.SimpleText := 'Start Simple Database Documentation';


      LibRvSystem.Execute;


      MainStatusBar.SimpleText := 'Documentation -> done ! ';
end;

end.

Open in new window

My point in all of what I have written so far is that you do NOT need to do a completely code based report!  You can do some relatively simple Delphi code to prepare for a non-code based report.

1) Start by doing normal database programming in a loop going through your records...

  While not MyDataset.EOF do
    ...
  end;

  For each record (...) you will do the extraction of the data needed by your report from the
  XML in the individual dataset fields.  There are an absolute TON of examples of extracting
  data from XML, so I will not reproduce them now.  If you want me to, I will add some XML
  links.  (This is the part where SEEING some of your XML data as an example would actually
  allow an expert to show you how to do it).

  Place the extracted data into an in memory dataset, or temporary dataset for use by RAVE.

2) Now that you have the data in the format that is easy for Rave to use, go into Rave and use the report wizard to get your report started.
One more time, in case you missed it, you are going about this the hard way!  Doing a code based report is FAR more work than what I am suggesting.
Avatar of BdLm

ASKER

Ok,  can you create a *.rav report file for 1 record one page and a style like the layout a proposed ?
I am going to have to create a custom database because the one you suggested has no "XML within fields" like you are looking for.  I will do this first and give you some instructions on how to recreate it on your end, so we have some basis to work from.  I will let you know...
What version of Delphi are you using?  I have access to Delphi 2010 and Delphi XE.
Avatar of BdLm

ASKER

I can work with Delphi 2010  - no problem.

* meanwhile here at EE I could make the draft version - rave code based -
   what I don't  like here - it is the same ugly code as writing driectly to the printer -
   no Objects- no classes  - no structure
 

really interessted to see the difference
unit Unit_LibraryReportTool;
{ *****************************************************************************
  *
  *
  *       DEMO  DUMP the Content of the Borland biolife.db with RAVE reports
  *
  *
  *       http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_26887858.html?cid=239#a35148858
  *       http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_26854889.html
  *       http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_26887858.html
  *
  *****************************************************************************}

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, StdCtrls,  DB, Grids,
  DBGrids, DBTables, ComCtrls, ExtCtrls,

  //  RAVE
  RpRave, RpDefine, RpCon, RpConDS,

  RPMEMO, RPDBUTIL,


  RpBase, RpSystem, RpConBDE, DBCtrls ;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Exit1: TMenuItem;
    ReportTable: TTable;
    DataSource1: TDataSource;
    LoadLibararyDB1: TMenuItem;
    MainStatusBar: TStatusBar;
    Report1: TMenuItem;
    StartReport1: TMenuItem;
    Panel1: TPanel;
    Label1: TLabel;
    ListBox1: TListBox;
    RvTableConnection1: TRvTableConnection;
    LibRvSystem: TRvSystem;
    RvProject1: TRvProject;
    ableReport1: TMenuItem;
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    DBGrid1: TDBGrid;
    DBImage1: TDBImage;
    DBMemo1: TDBMemo;
    ReportTableSpeciesNo: TFloatField;
    ReportTableCategory: TStringField;
    ReportTableCommon_Name: TStringField;
    ReportTableSpeciesName: TStringField;
    ReportTableLengthcm: TFloatField;
    ReportTableLength_In: TFloatField;
    ReportTableNotes: TMemoField;
    ReportTableGraphic: TGraphicField;
    procedure Exit1Click(Sender: TObject);
    procedure LoadLibararyDB1Click(Sender: TObject);
    procedure StartReport1Click(Sender: TObject);
    procedure LibRvSystemPrint(Sender: TObject);
    procedure LibRvSystemAfterPreviewPrint(Sender: TObject);
  private
    { Private-Deklarationen }
    FLibraryFilename   :  String;     ///  the name of the table for report
    ///
    ///
    procedure RavePrintDBmemo  ( PrintStart, PrintEnd : Real; YPos : Real ; AReport : TBasereport ) ;
    procedure RavePrintDBmemo2 ( PrintStart, PrintEnd : Real; YPos : Real ; AReport : TBasereport ) ;
    procedure RavePrintDBBitmap(XPOS, YPos, Xsize, YSize: Real; AReport: TBasereport);
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Exit1Click(Sender: TObject);
begin
      close;
end;

procedure TForm1.LoadLibararyDB1Click(Sender: TObject);
begin
      FLibraryFilename := 'e:\biolife.db';

      ReportTable.Active := false;

      ReportTable.TableName := FLibraryFilename;

      ReportTable.Active := true;


end;

procedure TForm1.LibRvSystemAfterPreviewPrint(Sender: TObject);
begin

end;

///
///
///
procedure TForm1.LibRvSystemPrint(Sender: TObject);
const tab1=0.2;
      tab2=1.7;
      tab3=3.2;
      tab4=4.0;
      tab5=5.0;

var    i          :  Integer;
       dbstring   :  String;
begin


     LibRvSystem.SystemPrinter.Orientation := poLandScape; // or poPortrait





      with Sender as TBaseReport do
        begin






        SetFont('ARIAL',15);

        Print ('Welcome to the rave demo report project (printing biolife.db) !!');




        GoToXY(1,1);
        NewLine;
        NewLine;

        ClearTabs;
        SetTab(tab1,pjLeft,tab2, 0,0,0);
        SetTab(tab2,pjLeft,tab3, 0,0,0);
        SetTab(tab3,pjLeft,tab4, 0,0,0);
        SetTab(tab4,pjLeft,tab5, 0,0,0);

        Bold := true;
        SetFont('ARIAL',10);


        PrintTab('Species No');
        PrintTab('Category');
        PrintTab('Common_Name');
        PrintTab('species Name ');

        FinishTabBox(1);

        Newline;
        Bold := false;

        for i:= 1 to ReportTable.RecordCount  do
             begin


            // canvas.brush.color := clred;
            // rectangle (0.1, 0.1, 6, 0.2);


             newline;

             dbstring := ReportTable.FieldByName('Species No').asstring;
             PrintTab(dbstring);

             dbstring := ReportTable.FieldByName('Category').asstring;
             PrintTab(dbstring);


             dbstring := ReportTable.FieldByName('Common_Name').asstring;
             PrintTab(dbstring);


             dbstring := ReportTable.FieldByName('Species Name').asstring;
             PrintTab(dbstring);

             // FinishTabBox(1);


             NewLine;


             RavePrintDBmemo(3,5, 1, (sender as Tbasereport) );

             RavePrintDBBitmap(1,1,2,2, (sender as Tbasereport) );



             // RavePrintDBmemo2(3,5, 1, (sender as Tbasereport) );


             ReportTable.Next;



             ///   1 record on 1 page

             NewPage;

             end;








        end;
end;




procedure TForm1.RavePrintDBBitmap ( XPOS, YPos , Xsize, YSize : Real ; AReport : TBasereport );
var  Bitmap              : TBitmap;
     TableGraphicField   : TGraphicField;
begin


        // TableGraphicField := ;

        Bitmap := TBitmap.Create;
        try

          GraphicFieldToBitmap( ReportTableGraphic  , Bitmap);
          AReport.PrintBitmapRect(XPos,YPos,XPos + Xsize, YPos + YSize,Bitmap);
        finally
          Bitmap.Free;
        end;

end;



procedure TForm1.RavePrintDBmemo ( PrintStart, PrintEnd : Real; YPos : Real ; AReport : TBasereport ) ;
var  MemBuf   : TDBMemoBuf;
     dbstring : String;
     i        : Integer;
     isEOL    : Boolean;
begin





  MemBuf := TDBMemoBuf.Create;
  with ReportTable do
    begin

        YPos := YPos + 0.5;

        AReport.GoToXY(PrintStart,YPos);
        MemBuf.PrintStart := PrintStart;
        MemBuf.PrintEnd := PrintEnd ;
        MemBuf.text := Reporttable.FieldByName('Notes').AsString;
        MemBuf.NoCRLF := False;
            for I := 1 to 5 do
              begin
                dbstring := AReport.GetMemoLine(MemBuf, isEOL);
                if dbstring <> '' then
                  begin
                    YPos := YPos + 0.15;
                    AReport.GoToXY(PrintEnd,YPos);
                    AReport.PrintLn(dbstring);  // PrintTab
                  end;
              end;
            YPos := YPos + 0.2;


    MemBuf.Free;
    end;
end;





procedure TForm1.RavePrintDBmemo2 ( PrintStart, PrintEnd : Real; YPos : Real ; AReport : TBasereport ) ;

var  Memobuf : TDBMemobuf;
     Lines : Integer;
begin






  With AReport do begin

    try
     Memobuf := TDBMemobuf.Create;

     Memobuf.PrintStart := TabStart(3);

     Memobuf.PrintEnd := TabEnd(3);

     MemoBuf.text := Reporttable.FieldByName('Notes').AsString;; // Table1Notes is the name of the field "Notes" in the TTable

     Lines := MemoLines(Memobuf);

     If Lines < 8 then
         begin
          Lines := 8;
         end;

     PrintMemo(Memobuf,Lines,true);


     finally
      Memobuf.Free;
     end;
  end;
end;




procedure TForm1.StartReport1Click(Sender: TObject);
begin
      ////

      MainStatusBar.SimpleText := 'Start Simple Database Documentation';


      LibRvSystem.Execute;


      MainStatusBar.SimpleText := 'Documentation -> done ! ';
end;

end.

Open in new window

I almost have the data example set up.  I have two records that have the following fields:
  <FIELD attrname="ID" fieldtype="i4" />
  <FIELD attrname="Name" fieldtype="string" WIDTH="100" />
  <FIELD attrname="Source" fieldtype="string" WIDTH="250" />
  <FIELD attrname="NutritionFacts" fieldtype="bin.hex" SUBTYPE="Text" />
  <FIELD attrname="Ingredients" fieldtype="bin.hex" SUBTYPE="Text" />
  <FIELD attrname="Preparation" fieldtype="bin.hex" SUBTYPE="Text" />
  <FIELD attrname="SmallImage" fieldtype="bin.hex" SUBTYPE="Graphics" />
  <FIELD attrname="LargeImage" fieldtype="bin.hex" SUBTYPE="Graphics" />

I set them up in a TClientDataset and I have a small example program that allows me to load and save the data as XML.  I had to come up with SOME FORM of example data that loosely matched your criteria since I had none to work with.  This is a database of recipes where each record has a recipe name, a source field (used for URL), Nutrition Facts (XML), Ingredients (XML), Preparation (could be text or XML) and two image fields that I left unused to keep the transmission small.

My goal will be to show a simple way to create a report in RAVE using this data.  One record per page, including data extracted from the XML field NutritionFacts.

Here is the DFM portion that sets up the CDS:

  object cdsRecipes: TClientDataSet
    Active = True
    Aggregates = <>
    Params = <>
    Left = 432
    Top = 8
    Data = {
      250100009619E0BD010000001800000008000000000003000000250102494404
      00010000000000044E616D650100490000000100055749445448020002006400
      06536F75726365010049000000010005574944544802000200FA000E4E757472
      6974696F6E466163747304004B00000001000753554254595045020049000500
      54657874000B496E6772656469656E747304004B000000010007535542545950
      4502004900050054657874000B5072657061726174696F6E04004B0000000100
      075355425459504502004900050054657874000A536D616C6C496D6167650400
      4B000000010007535542545950450200490009004772617068696373000A4C61
      726765496D61676504004B000000010007535542545950450200490009004772
      617068696373000000}
    object cdsRecipesID: TIntegerField
      AutoGenerateValue = arAutoInc
      FieldName = 'ID'
    end
    object cdsRecipesName: TStringField
      FieldName = 'Name'
      Size = 100
    end
    object cdsRecipesSource: TStringField
      FieldName = 'Source'
      Size = 250
    end
    object cdsRecipesNutritionFacts: TMemoField
      FieldName = 'NutritionFacts'
      BlobType = ftMemo
    end
    object cdsRecipesIngredients: TMemoField
      FieldName = 'Ingredients'
      BlobType = ftMemo
    end
    object cdsRecipesPreparation: TMemoField
      FieldName = 'Preparation'
      BlobType = ftMemo
    end
    object cdsRecipesSmallImage: TGraphicField
      FieldName = 'SmallImage'
      BlobType = ftGraphic
    end
    object cdsRecipesLargeImage: TGraphicField
      FieldName = 'LargeImage'
      BlobType = ftGraphic
    end
  end

Here is the XML that I persist to disk.  This can be loaded and assigned to the cds.XMLData property to load the data in.

  <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
- <DATAPACKET Version="2.0">
- <METADATA>
- <FIELDS>
  <FIELD attrname="ID" fieldtype="i4" /> 
  <FIELD attrname="Name" fieldtype="string" WIDTH="100" /> 
  <FIELD attrname="Source" fieldtype="string" WIDTH="250" /> 
  <FIELD attrname="NutritionFacts" fieldtype="bin.hex" SUBTYPE="Text" /> 
  <FIELD attrname="Ingredients" fieldtype="bin.hex" SUBTYPE="Text" /> 
  <FIELD attrname="Preparation" fieldtype="bin.hex" SUBTYPE="Text" /> 
  <FIELD attrname="SmallImage" fieldtype="bin.hex" SUBTYPE="Graphics" /> 
  <FIELD attrname="LargeImage" fieldtype="bin.hex" SUBTYPE="Graphics" /> 
  </FIELDS>
  <PARAMS CHANGE_LOG="1 0 4 2 0 4" /> 
  </METADATA>
- <ROWDATA>
  <ROW RowState="4" ID="1" Name="Whole Grain Oatmeal" Source="http://www.bobsredmill.com/gluten-free-rolled-oats.html" NutritionFacts="<NutritionFacts> <ServingSize> 1/2 cup dry </ServingSize> <Calories> 190 </Calories> <Cholesterol> 0 mg </Cholesterol> <Sodium> 0 mg </Sodium> <Carbohydrate> 32 g <DietaryFiber> 5 g </DietaryFiber> <Sugars> 1 g </Sugars> </Carbohydrate> <Protein> 7 g </Protein> <VitaminA> 0% </VitaminA> <VitaminC> 0% </VitaminC> <Calcium> 2% </Calcium> <Iron> 15% </Iron> </NutritionFacts>" Ingredients="<Ingredients> <Ingredient> 1/2 cup whole grain oats </Ingredient> <Ingredient> 1 cup water </Ingredient> </Ingredients>" Preparation="<Preparation> </Preparatrion>" /> 
  <ROW RowState="4" ID="2" Name="Long Grain Brown Rice" Source="http://www.bobsredmill.com/basmati-brown-rice.html" NutritionFacts="<NutritionFacts> <ServingSize> 1/4 cup </ServingSize> <Calories> 170 </Calories> <Cholesterol> 0 mg </Cholesterol> <Sodium> 0 mg </Sodium> <Carbohydrate> 38 g <DietaryFiber> 2 g </DietaryFiber> <Sugars> 0 g </Sugars> </Carbohydrate> <Protein> 4 g </Protein> <VitaminA> 0% </VitaminA> <VitaminC> 0% </VitaminC> <Calcium> 0% </Calcium> <Iron> 2% </Iron> </NutritionFacts>" Ingredients="<Ingredients> <Ingredient> 1/4 cup whole grain oats </Ingredient> <Ingredient> 5/8 cup water </Ingredient> </Ingredients>" Preparation="<Preparation> </Preparatrion>" /> 
  </ROWDATA>
  </DATAPACKET>

Open in new window

The first step was to generate the data that would be used.  Trying to keep it simple I created this XML file.  It is not optimized XML, nor is it complete data.  It is just for an example here.  I changed it slightly to make the example easier.


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>  <DATAPACKET Version="2.0"><METADATA><FIELDS><FIELD attrname="ID" fieldtype="i4"/><FIELD attrname="Name" fieldtype="string" WIDTH="100"/><FIELD attrname="Source" fieldtype="string" WIDTH="250"/><FIELD attrname="NutritionFacts" fieldtype="bin.hex" SUBTYPE="Text"/><FIELD attrname="Ingredients" fieldtype="bin.hex" SUBTYPE="Text"/><FIELD attrname="Preparation" fieldtype="bin.hex" SUBTYPE="Text"/><FIELD attrname="SmallImage" fieldtype="bin.hex" SUBTYPE="Graphics"/><FIELD attrname="LargeImage" fieldtype="bin.hex" SUBTYPE="Graphics"/></FIELDS><PARAMS CHANGE_LOG="1 0 4 2 1 8 3 0 4"/></METADATA><ROWDATA><ROW RowState="5" ID="1" Name="Whole Grain Oatmeal" Source="http://www.bobsredmill.com/gluten-free-rolled-oats.html&#013;&#010;http://www.bobsredmill.com/gluten-free-rolled-oats.html&#013;&#010;http://www.bobsredmill.com/gluten-free-rolled-oats.html&#013;&#010;"/><ROW RowState="12" ID="1" Name="Whole Grain Oatmeal" Source="http://www.bobsredmill.com/gluten-free-rolled-oats.html&#013;&#010;&#013;&#010;" NutritionFacts="&lt;NutritionFacts&gt;&#013;&#010;  &lt;ServingSize&gt;&#013;&#010;    1/2 cup dry&#013;&#010;  &lt;/ServingSize&gt;&#013;&#010;  &lt;Calories&gt;&#013;&#010;    190&#013;&#010;  &lt;/Calories&gt;&#013;&#010;  &lt;Cholesterol&gt;&#013;&#010;    0 mg&#013;&#010;  &lt;/Cholesterol&gt;&#013;&#010;  &lt;Sodium&gt;&#013;&#010;    0 mg&#013;&#010;  &lt;/Sodium&gt;&#013;&#010;  &lt;Carbohydrate&gt;&#013;&#010;    32 g&#013;&#010;  &lt;/Carbohydrate&gt;&#013;&#010;  &lt;DietaryFiber&gt;&#013;&#010;    5 g&#013;&#010;  &lt;/DietaryFiber&gt;&#013;&#010;  &lt;Sugars&gt;&#013;&#010;    1 g&#013;&#010;  &lt;/Sugars&gt;&#013;&#010;  &lt;Protein&gt;&#013;&#010;    7 g&#013;&#010;  &lt;/Protein&gt;&#013;&#010;  &lt;VitaminA&gt;&#013;&#010;    0%&#013;&#010;  &lt;/VitaminA&gt;&#013;&#010;  &lt;VitaminC&gt;&#013;&#010;    0%&#013;&#010;  &lt;/VitaminC&gt;&#013;&#010;  &lt;Calcium&gt;&#013;&#010;    2%&#013;&#010;  &lt;/Calcium&gt;&#013;&#010;  &lt;Iron&gt;&#013;&#010;    15%&#013;&#010;  &lt;/Iron&gt;&#013;&#010;&lt;/NutritionFacts&gt;" Ingredients="&lt;Ingredients&gt;&#013;&#010;  &lt;Ingredient&gt;&#013;&#010;    1/2 cup whole grain oats&#013;&#010;  &lt;/Ingredient&gt;&#013;&#010;  &lt;Ingredient&gt;&#013;&#010;    1 cup water&#013;&#010;  &lt;/Ingredient&gt;&#013;&#010;&lt;/Ingredients&gt;" Preparation="&lt;Preparation&gt;&#013;&#010;&lt;/Preparatrion&gt;"/><ROW RowState="4" ID="2" Name="Long Grain Brown Rice" Source="http://www.bobsredmill.com/basmati-brown-rice.html" NutritionFacts="&lt;NutritionFacts&gt;&#013;&#010;  &lt;ServingSize&gt;&#013;&#010;    1/4 cup&#013;&#010;  &lt;/ServingSize&gt;&#013;&#010;  &lt;Calories&gt;&#013;&#010;    170&#013;&#010;  &lt;/Calories&gt;&#013;&#010;  &lt;Cholesterol&gt;&#013;&#010;    0 mg&#013;&#010;  &lt;/Cholesterol&gt;&#013;&#010;  &lt;Sodium&gt;&#013;&#010;    0 mg&#013;&#010;  &lt;/Sodium&gt;&#013;&#010;  &lt;Carbohydrate&gt;&#013;&#010;    38 g&#013;&#010;  &lt;/Carbohydrate&gt;&#013;&#010;  &lt;DietaryFiber&gt;&#013;&#010;    2 g&#013;&#010;  &lt;/DietaryFiber&gt;&#013;&#010;  &lt;Sugars&gt;&#013;&#010;    0 g&#013;&#010;  &lt;/Sugars&gt;&#013;&#010;  &lt;Protein&gt;&#013;&#010;    4 g&#013;&#010;  &lt;/Protein&gt;&#013;&#010;  &lt;VitaminA&gt;&#013;&#010;    0%&#013;&#010;  &lt;/VitaminA&gt;&#013;&#010;  &lt;VitaminC&gt;&#013;&#010;    0%&#013;&#010;  &lt;/VitaminC&gt;&#013;&#010;  &lt;Calcium&gt;&#013;&#010;    0%&#013;&#010;  &lt;/Calcium&gt;&#013;&#010;  &lt;Iron&gt;&#013;&#010;    2%&#013;&#010;  &lt;/Iron&gt;&#013;&#010;&lt;/NutritionFacts&gt;" Ingredients="&lt;Ingredients&gt;&#013;&#010;  &lt;Ingredient&gt;&#013;&#010;    1/4 cup whole grain oats&#013;&#010;  &lt;/Ingredient&gt;&#013;&#010;  &lt;Ingredient&gt;&#013;&#010;    5/8 cup water&#013;&#010;  &lt;/Ingredient&gt;&#013;&#010;&lt;/Ingredients&gt;" Preparation="&lt;Preparation&gt;&#013;&#010;&lt;/Preparatrion&gt;"/></ROWDATA></DATAPACKET>

Open in new window

Save the data as Recipes.XML in the directory you intend to run the program from (again for simplicity).  Here is the DFM and PAS for the program as it stands now.  If you need help with this portion, let me know.
---DFM---
object fInputMain: TfInputMain
  Left = 0
  Top = 0
  Caption = 'Recipes'
  ClientHeight = 529
  ClientWidth = 612
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  Menu = MainMenu1
  OldCreateOrder = False
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Splitter1: TSplitter
    Left = 0
    Top = 120
    Width = 612
    Height = 3
    Cursor = crVSplit
    Align = alTop
    ExplicitWidth = 344
  end
  object Splitter2: TSplitter
    Left = 0
    Top = 241
    Width = 612
    Height = 3
    Cursor = crVSplit
    Align = alTop
    ExplicitTop = 128
    ExplicitWidth = 900
  end
  object Splitter3: TSplitter
    Left = 0
    Top = 379
    Width = 612
    Height = 3
    Cursor = crVSplit
    Align = alTop
    ExplicitTop = 249
  end
  object DBGrid1: TDBGrid
    Left = 0
    Top = 0
    Width = 612
    Height = 120
    Align = alTop
    DataSource = dsRecipes
    TabOrder = 0
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'Tahoma'
    TitleFont.Style = []
    Columns = <
      item
        Expanded = False
        FieldName = 'ID'
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'Name'
        Title.Caption = 'Recipe Name'
        Width = 200
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'Source'
        Width = 200
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'NutritionFacts'
        Visible = False
      end
      item
        Expanded = False
        FieldName = 'Ingredients'
        Visible = False
      end
      item
        Expanded = False
        FieldName = 'SmallImage'
        Visible = False
      end
      item
        Expanded = False
        FieldName = 'LargeImage'
        Visible = False
      end>
  end
  object Panel1: TPanel
    Left = 0
    Top = 123
    Width = 612
    Height = 118
    Align = alTop
    TabOrder = 1
    object Label2: TLabel
      Left = 1
      Top = 1
      Width = 610
      Height = 13
      Align = alTop
      AutoSize = False
      Caption = 'Nutrition Facts'
      ExplicitTop = 5
      ExplicitWidth = 70
    end
    object DBMemo1: TDBMemo
      Left = 1
      Top = 14
      Width = 610
      Height = 103
      Align = alClient
      DataField = 'NutritionFacts'
      DataSource = dsRecipes
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Courier'
      Font.Style = []
      ParentFont = False
      TabOrder = 0
      ExplicitLeft = 0
      ExplicitTop = 13
    end
  end
  object Panel2: TPanel
    Left = 0
    Top = 244
    Width = 612
    Height = 135
    Align = alTop
    TabOrder = 2
    object Label1: TLabel
      Left = 1
      Top = 1
      Width = 610
      Height = 13
      Align = alTop
      AutoSize = False
      Caption = 'Ingredients XML'
      ExplicitTop = 5
      ExplicitWidth = 77
    end
    object DBMemo2: TDBMemo
      Left = 1
      Top = 14
      Width = 610
      Height = 120
      Align = alClient
      DataField = 'Ingredients'
      DataSource = dsRecipes
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Courier'
      Font.Style = []
      ParentFont = False
      TabOrder = 0
    end
  end
  object Panel3: TPanel
    Left = 0
    Top = 382
    Width = 612
    Height = 147
    Align = alClient
    TabOrder = 3
    object Label3: TLabel
      Left = 1
      Top = 1
      Width = 610
      Height = 13
      Align = alTop
      AutoSize = False
      Caption = 'Preparation'
      ExplicitLeft = 0
      ExplicitTop = -5
    end
    object DBMemo3: TDBMemo
      Left = 1
      Top = 14
      Width = 610
      Height = 132
      Align = alClient
      DataField = 'Preparation'
      DataSource = dsRecipes
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Courier'
      Font.Style = []
      ParentFont = False
      TabOrder = 0
    end
  end
  object dsRecipes: TDataSource
    DataSet = cdsRecipes
    Left = 496
    Top = 8
  end
  object cdsRecipes: TClientDataSet
    Active = True
    Aggregates = <>
    Params = <>
    Left = 432
    Top = 8
    Data = {
      250100009619E0BD010000001800000008000000000003000000250102494404
      00010000000000044E616D650100490000000100055749445448020002006400
      06536F75726365010049000000010005574944544802000200FA000E4E757472
      6974696F6E466163747304004B00000001000753554254595045020049000500
      54657874000B496E6772656469656E747304004B000000010007535542545950
      4502004900050054657874000B5072657061726174696F6E04004B0000000100
      075355425459504502004900050054657874000A536D616C6C496D6167650400
      4B000000010007535542545950450200490009004772617068696373000A4C61
      726765496D61676504004B000000010007535542545950450200490009004772
      617068696373000000}
    object cdsRecipesID: TIntegerField
      AutoGenerateValue = arAutoInc
      FieldName = 'ID'
    end
    object cdsRecipesName: TStringField
      FieldName = 'Name'
      Size = 100
    end
    object cdsRecipesSource: TStringField
      FieldName = 'Source'
      Size = 250
    end
    object cdsRecipesNutritionFacts: TMemoField
      FieldName = 'NutritionFacts'
      BlobType = ftMemo
    end
    object cdsRecipesIngredients: TMemoField
      FieldName = 'Ingredients'
      BlobType = ftMemo
    end
    object cdsRecipesPreparation: TMemoField
      FieldName = 'Preparation'
      BlobType = ftMemo
    end
    object cdsRecipesSmallImage: TGraphicField
      FieldName = 'SmallImage'
      BlobType = ftGraphic
    end
    object cdsRecipesLargeImage: TGraphicField
      FieldName = 'LargeImage'
      BlobType = ftGraphic
    end
  end
  object MainMenu1: TMainMenu
    Left = 552
    Top = 8
    object File1: TMenuItem
      Caption = '&File'
      object Save1: TMenuItem
        Caption = '&Save'
        OnClick = Save1Click
      end
      object Print1: TMenuItem
        Caption = '&Print...'
        OnClick = Print1Click
      end
      object Exit1: TMenuItem
        Caption = 'E&xit'
        OnClick = Exit1Click
      end
    end
    object Edit1: TMenuItem
      Caption = '&Edit'
      object NewRecipe1: TMenuItem
        Caption = '&New Recipe'
        ShortCut = 45
        OnClick = NewRecipe1Click
      end
      object DeleteRecipe1: TMenuItem
        Caption = 'Delete Recipe'
        ShortCut = 46
        OnClick = DeleteRecipe1Click
      end
    end
  end
  object XMLDocument1: TXMLDocument
    Options = [doAttrNull, doAutoPrefix, doNamespaceDecl]
    Left = 432
    Top = 64
    DOMVendorDesc = 'MSXML'
  end
  object RaveDSConn: TRvDataSetConnection
    RuntimeVisibility = rtDeveloper
    Left = 432
    Top = 144
  end
end

--PAS---
unit frmInputMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, DBClient, Grids, DBGrids, StdCtrls, DBCtrls, ExtCtrls, Menus,
  xmldom, XMLIntf, msxmldom, XMLDoc, RpDefine, RpCon, RpConDS;

type
  TfInputMain = class(TForm)
    DBGrid1: TDBGrid;
    dsRecipes: TDataSource;
    Splitter1: TSplitter;
    Panel1: TPanel;
    DBMemo1: TDBMemo;
    Label2: TLabel;
    Splitter2: TSplitter;
    Panel2: TPanel;
    DBMemo2: TDBMemo;
    Label1: TLabel;
    cdsRecipes: TClientDataSet;
    cdsRecipesID: TIntegerField;
    cdsRecipesName: TStringField;
    cdsRecipesSource: TStringField;
    cdsRecipesNutritionFacts: TMemoField;
    cdsRecipesIngredients: TMemoField;
    cdsRecipesPreparation: TMemoField;
    cdsRecipesSmallImage: TGraphicField;
    cdsRecipesLargeImage: TGraphicField;
    Panel3: TPanel;
    Label3: TLabel;
    DBMemo3: TDBMemo;
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Save1: TMenuItem;
    Print1: TMenuItem;
    Exit1: TMenuItem;
    Edit1: TMenuItem;
    NewRecipe1: TMenuItem;
    DeleteRecipe1: TMenuItem;
    Splitter3: TSplitter;
    XMLDocument1: TXMLDocument;
    RaveDSConn: TRvDataSetConnection;
    procedure Exit1Click(Sender: TObject);
    procedure Save1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure NewRecipe1Click(Sender: TObject);
    procedure DeleteRecipe1Click(Sender: TObject);
    procedure Print1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    fDirectory : string;
    fFileName : string;

    function StripWhiteSpace(Value : string) : string;
  public
    cdsReport : TClientDataset;
  end;

var
  fInputMain: TfInputMain;

implementation

{$R *.dfm}

procedure TfInputMain.DeleteRecipe1Click(Sender: TObject);
begin
  if cdsRecipes.State <> dsBrowse then
    cdsRecipes.Post;

  if MessageDlg('Are you sure you want to delete this recipe?', mtConfirmation,
    [mbOK, mbCancel], 0) = mrOK then
    cdsRecipes.Delete;
end;

procedure TfInputMain.Exit1Click(Sender: TObject);
begin
  Close;
end;

procedure TfInputMain.FormCreate(Sender: TObject);
var
  S : string;
  SL : TStringList;

begin
  fDirectory := ExtractFilePath(ParamStr(0));
  fFileName := fDirectory + '\Recipes.XML';

  if FileExists(fFileName) then
    begin
      SL := TStringList.Create;
      try
        SL.LoadFromFile(fFileName);
        S := SL.Text;
        cdsRecipes.XMLData := S;
      finally
        SL.Free;
      end;
    end;
end;

procedure TfInputMain.FormDestroy(Sender: TObject);
begin
  FreeAndNil(cdsReport);
end;

procedure TfInputMain.NewRecipe1Click(Sender: TObject);
begin
  cdsRecipes.Append;
end;

procedure TfInputMain.Print1Click(Sender: TObject);
var
  Bookmark1 : integer;
  X, Calories, Protein, Carbs : string;
  Doc : IXMLNode;

begin
  {code based portion of the report}
  if cdsRecipes.State <> dsBrowse then
    cdsRecipes.Post;

  Bookmark1 := cdsRecipesID.AsInteger; {prepare to move back to this record}

  {Disable visual control updates for controls attached to this CDS.}
  cdsRecipes.DisableControls;

  {This will do nothing if cdsReport is nil.  Destroying it here, and when the
   form is destroyed will allow the Rave report designer to work with it
   freely when the program is running (an aid to easily designing the report)}
  FreeAndNil(cdsReport);

  {create the client dataset to be passed to the report}
  cdsReport := TClientDataset.Create(nil);
  try
    cdsReport.FieldDefs.Add('RecipeName', ftString, 100);
    cdsReport.FieldDefs.Add('Source', ftString, 250);
    cdsReport.FieldDefs.Add('Calories', ftString, 10);
    cdsReport.FieldDefs.Add('Protein', ftString, 10);
    cdsReport.FieldDefs.Add('Carbs', ftString, 10);
    cdsReport.CreateDataSet;

    {roll through the records extracting data to cdsReport}
    cdsRecipes.First;
    while not cdsRecipes.Eof do
      begin
        cdsReport.Append;
        cdsReport.FieldByName('RecipeName').AsString := cdsRecipesName.AsString;
        cdsReport.FieldByName('Source').AsString := cdsRecipesSource.AsString;

        {Here is where the XML extraction is done...}
        X := cdsRecipesNutritionFacts.AsString;
        XMLDocument1.LoadFromXML(X);
        Doc := XMLDocument1.DocumentElement;
        Calories := StripWhiteSpace(Doc.ChildValues['Calories']);
        Protein := StripWhiteSpace(Doc.ChildValues['Protein']);
        Carbs := StripWhiteSpace(Doc.ChildValues['Carbohydrate']);
        XMLDocument1.Active := false;

        cdsReport.FieldByName('Calories').AsString := Calories;
        cdsReport.FieldByName('Protein').AsString := Protein;
        cdsReport.FieldByName('Carbs').AsString := Carbs;

        cdsReport.Post;
        cdsRecipes.Next;
      end;

      {at this point we have the report ready data}
      RaveDSConn.DataSet := cdsReport;

  finally
    {go back to the bookmarked record}
    cdsRecipes.Locate('ID', VarArrayOf([Bookmark1]), []);

    {re-enable the visual controls attached to the CDS}
    cdsRecipes.EnableControls;
  end;
end;

procedure TfInputMain.Save1Click(Sender: TObject);
var
  S : string;
  SL : TStringList;

begin
  if cdsRecipes.State <> dsBrowse then
    cdsRecipes.Post;

  S := cdsRecipes.XMLData;
  SL := TStringList.Create;
  try
    SL.Text := S;
    SL.SaveToFile(fFileName);
  finally
    SL.Free;
  end;
end;

function TfInputMain.StripWhiteSpace(Value: string): string;
var
  First, C, Last : PWideChar;
  R : string;

begin
  First := @Value[1];
  while (First <> #0) and CharInSet(First^, [' ', #9, #10, #13]) do
    First := StrNextChar(First);

  C := StrNextChar(First);
  while C^ <> #0 do
    begin
      if not CharInSet(C^, [' ', #9, #10, #13]) then
        Last := C;
      C := StrNextChar(C);
    end;

  C := First;
  R := '';
  while C <> Last do
    begin
      R := R + C^;
      C := StrNextChar(C);
    end;
  R := R + Last^;

  Result := R;
end;

end.

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of developmentguru
developmentguru
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Once the report is done you would save it where you need to in order to incorporate it into your program.  From this point you would just place the non-visual controls as usual and add the code to the File | Print to actually call it up.
Avatar of BdLm

ASKER


I received a further request to my report.

On the right side bitmap , i have to mark several postions by a circle  or a cross symbol.
In the XML DB memo field is the information - how many points should be marked , where to draw the marks ....


Can I extent your code in principle to that functionality ?

In Rave the functionality of selecting a bitmap based on a data field value is quite simple using scripting.  The scripting is in a pascal script, so it is quite easy for someone used to Delphi.  Since my code shows how to extract any fields from the XML into a flat style dataset for use in the Rave report, the new requests should pose no problems.

I would need to see some graphical representation of the desired output in order to have any more comment...
Avatar of BdLm

ASKER

@ devguru : thanks for your help and code