Hi,
>The problem is when the foreach doesn't output any data, in this case we can't use the "Finish Report" command, this will cause an "Expression error" because the report was expecting data a
You are getting the error because you are accessing look-ahead variables from a list (trigger) that is empty. That typically happens in report headers where you access for example the customer name that is shipped in the order details. If the report has no order details then the header references a variable that is not shipped and an error is raised.
There are two patterns to avoid that as follows:
Pattern 1:
1) Add a variable to your report and declare is as the first variable in your ORDER EXTERNAL.
2) Populate the variable with a constant value in OUTPUT TO REPORT.
Example introducing the variable "k" in the report as described:
START REPORT myreport TO XML HANDLER handler
FOREACH ...
OUTPUT TO REPORT myreport(1,rec.*) #Note that k is always 1
END FOREACH
FINISH REPORT myreport
REPORT myreport(k,rec)
DEFINE k INTEGER, rec RECORD LIKE ...
ORDER EXTERNAL BY k,rec....
END REPORT
In the report designer you will have a trigger for "Group k" in which you place your entire report content including the page root(s). In the case the OUTPUT TO REPORT is never called, the trigger "k" will not be executed and the report will not produce any output at all and no errors will be raised.
The pattern has the additional benefit that you can have a trigger "BEFORE GROUP OF k" that is the equivalent of "FIRST PAGE HEADER" but allows you to put a dynamic number of PRINT inside (That is not allowed in FIRST PAGE HEADER). This way you could for example have a dynamic list of items in the page header.
Pattern 2 (Code not tested):
Delay the output by always reading ahead one record as follows:
Example code before the change:
DEFINE orderline OrderType
..
START REPORT report_all_orders TO XML HANDLER handler
FOREACH c_order INTO orderline.*
OUTPUT TO REPORT report_all_orders(orderline.*)
END FOREACH
FINISH REPORT report_all_orders
Example code after the change:
DEFINE orderline, nextRow OrderType,
startedReport BOOLEAN
..
LET startedReport=FALSE
FOREACH c_order INTO nextRow.*
IF NOT startedReport THEN
LET startedReport=TRUE
START REPORT report_all_orders TO XML HANDLER handler
ELSE
OUTPUT TO REPORT report_all_orders(orderline.*)
END IF
LET orderline.*=nextRow.*
END FOREACH
IF startedReport THEN
OUTPUT TO REPORT report_all_orders(orderline.*)
FINISH REPORT report_all_orders
END IF
Regards,
Alex