Professional Documents
Culture Documents
APEX Office Print Manual PDF
APEX Office Print Manual PDF
Provided by:
(https://www.apexrnd.be)
1 About AOP
1.1 Goal
APEX Office Print makes printing and exporting (docx, xlsx, pptx, pdf, html, md, txt, csv, ics) in Oracle
Application Express (APEX) or just in PL/SQL a lot easier.
Make a template in Office, HTML or Markdown, choose data from your database and merge them into one. You
can easily print PDFs, Office documents, HTML or Markdown in no time. It saves you time and effort by creating
templates in which you can easily integrate your data.
APEX Office Print (AOP) is a product of APEX R&D, located in Leuven, Belgium.
We are an experienced partner that helps you facilitate, improve and accelerate your business through new and
innovative solutions. Built on in-depth technical expertise, our company provides custom-made IT services for
managing business data and processes.
1. Simple Printing It is fast, easy and saves you money. It's the only solution on the market that is fully
integrated with APEX. For example, you can print or export your Interactive Reports and Grids data in a
second.
2. Quick and Easy Setup Simply Import the APEX Plug-in in your application
3. Any Data Type Support Text, images, barcodes, formulas…. it is easy to merge your data with any
template you create
https://www.apexofficeprint.com/docs/ 1/197
6/9/2019 APEX Office Print
4. Scalable and Secure APEX Office Print is a scalable and secure product that fits your every printing
requirement.
5. PL/SQL API support It gives you the ability to run and retrieve reports from AOP server directly from your
PL/SQL code.
6. Optimized for Performance Great design with finest details to enhance your business productivity.
7. Flexible APEX Office Print is a print server allowing you to create templates in Word, Excel, and
PowerPoint for any type of data.
It's the database (APEX Plug-in, PL/SQL API, REST Webservice) that is doing a request to the AOP Server
(either on-premise or our cloud). The template together with the data is send in JSON format to the AOP Server.
The browser doesn't need to have access to the AOP server.
https://www.apexofficeprint.com/docs/ 2/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 3/197
6/9/2019 APEX Office Print
The APEX Office Print package consists of a server component, an Oracle APEX plug-in and PL/SQL API.
The server part returns generated documents upon receiving HTTP POST requests. These requests require a
structured JSON file that for example can be inferred from a SQL database. The data from the database in
combination with a template will generate relevant output files.
The Oracle Application Express (APEX) plug-in will generate the HTTP POST requests that the server part
understands. The plug-in makes it easy to select a template, your data source and the output format straight
from within your APEX application.
The PL/SQL API allows to print directly from the Oracle database. The PL/SQL API fits perfectly if you need to
setup automatic printing through a job or do a mail merge.
A sample application comes with the download, so you see plenty of use cases in action.
a cloud version, which will send the requests to APEX Office Print in the cloud
an on-premise version, which includes the server component of APEX Office Print. It's an executable you
run on your own server and in the APEX Plug-in you reference your own local version of APEX Office
Print. In this case nothing is sent to the AOP cloud.
1.7 License
This is commercial software; you need to obtain a valid license in order to use this software and plug-in in your
application. For the on-premise version a license is required per server (MID i.e. machine id) you are running
APEX Office Print of or you can go for an Enterprise License which is not tied to MID.
https://www.apexofficeprint.com/docs/ 4/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 5/197
6/9/2019 APEX Office Print
5. At the same time, you'll be logged into your AOP Dashboard. Select Downloads
https://www.apexofficeprint.com/docs/ 6/197
6/9/2019 APEX Office Print
In your AOP dashboard your unique API key number can be found under the Account Info region on the home
page. This number will need to be added to your Plug-in settings in order for it to work. For more information on
how to do this check the APEX Plugin Section.
2. Run aop_db_pkg.sql (in the "db"-directory) in your Oracle Schema (SQL Workshop -> SQL Scripts ->
Upload -> Select file and hit Upload)
4. On the page you want to use AOP, add the "APEX Office Print" Dynamic Action or Process
2. Run aop_db_pkg.sql (in the "db"-directory) in your Oracle Schema (SQL Workshop -> SQL Scripts ->
Upload -> Select file and hit Upload)
https://www.apexofficeprint.com/docs/ 7/197
6/9/2019 APEX Office Print
4. Optional: run aop_db_sample_pkg.sql (in the "db"-directory) in your Oracle Schema (SQL Workshop ->
SQL Scripts -> Upload -> Select file and hit Upload), which will create some sample PL/SQL Scripts. We
also recommend you to install the latest version of AOP Sample App.
5. For on-premises versions of AOP, on the server stop AOP, copy the server directory and restart AOP with
the new executable.
Note that the higher the APEX version, the more samples the AOP Sample App will include. We recommend
looking at the latest version of the AOP Sample App, even if you are not yet on the latest version of APEX. Many
examples will work in previous versions of APEX too, but they don't necessarily exist in that version of the AOP
Sample App.
In order to run the AOP Sample Application an Oracle APEX Packaged application called Sample Database
Application has to be installed first. The reason is that the source and templates are using data from the tables
(demo_orders, demo_order_items, demo_product_info, ….) which are installed by the packaged application.
https://www.apexofficeprint.com/docs/ 8/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 9/197
6/9/2019 APEX Office Print
6. Select to use existing Application ID Note: When you selected Auto Reassign Application ID you need to
make sure that you change the values of aop_api_pkg that uses APP_ID and AOP_URL as global
variables.
By inspecting elements of these pages, you can quickly learn how to use AOP Plug-in.
https://www.apexofficeprint.com/docs/ 10/197
6/9/2019 APEX Office Print
Note that the AOP Sample Application for APEX 5.0, 5.1 and 18.1 are different. The higher the APEX
version, the more features you will find in the AOP Sample App.
1. Sample Print
This page contains different buttons all linked to different AOP processes and dynamic actions that show
different use cases of the AOP plug-in.
2. Top Features
This section highlights some of the key differentiators of APEX Office Print compared to other print
solutions.
https://www.apexofficeprint.com/docs/ 11/197
6/9/2019 APEX Office Print
3. Dynamic Print
Dynamically you can select your template in Word, Excel or PowerPoint and output depending on the
customer you selected.
https://www.apexofficeprint.com/docs/ 12/197
6/9/2019 APEX Office Print
4. Reports Print
This section shows examples where a classic and interactive report and grid is used as the source of the
data. There is also an example to print labels. You can even use a combination of multiple classic and
interactive reports as your data source. This feature is one of the most impressive of AOP and not found
in any other tool.
https://www.apexofficeprint.com/docs/ 13/197
6/9/2019 APEX Office Print
5. Chart Print
This section shows examples how to print charts: Line, Bar, Column, Pie, Radar, Area, ... The charts are
native Office charts, so they can even be adapted after creation in Word, Excel and PowerPoint.
https://www.apexofficeprint.com/docs/ 14/197
6/9/2019 APEX Office Print
You can also write your mark-up in a Rich Text Editor and AOP will understand and translate the mark-up
(bold, color, etc.) into native Word markup. In your template you need to put an underscore in front of the
tag name e.g. {_htmlcontent}
https://www.apexofficeprint.com/docs/ 15/197
6/9/2019 APEX Office Print
7. Images
APEX Office Print is able to print images in different formats. This screen shows an example how to
configure it. In order to show images, you base64 encode those and put a % in your tag e.g. {%image}
https://www.apexofficeprint.com/docs/ 16/197
6/9/2019 APEX Office Print
8. QR and Barcodes
APEX Office Print is able to print different Bar- and QR codes. This screen shows an example how to
configure it.
https://www.apexofficeprint.com/docs/ 17/197
6/9/2019 APEX Office Print
9. Inline PDF
If you want to show the PDF inline in a modal dialog or in a certain div (region), this page shows exactly
how to do that. The value of the tag data-aop-inline-pdf should be the name of dynamic action that calls
AOP.
https://www.apexofficeprint.com/docs/ 18/197
6/9/2019 APEX Office Print
The Complex Print section shows different use cases for Word, Excel and PowerPoint. There are different
templates that show how to create more complex layouts. There are also some examples that show some
specific features like how to use line breaks in your data or how to download two documents at the same
time.
https://www.apexofficeprint.com/docs/ 19/197
6/9/2019 APEX Office Print
Word has a feature to create labels via the mailings option. This screen shows an example with some
specific Avery size labels.
https://www.apexofficeprint.com/docs/ 20/197
6/9/2019 APEX Office Print
This example shows how you can call a procedure and send an email as attachment. There is also an
option to send the email but also downloading the file.
https://www.apexofficeprint.com/docs/ 21/197
6/9/2019 APEX Office Print
Here you can see AOP PL/SQL API in action. It shows how to retrieve a document from AOP server and
store it in custom table. This is extremely useful when you want to schedule your print jobs and send
automated emails.
You can schedule a job to print every day, week, month etc. a specific report by using dbms_scheduler
and the AOP PL/SQL API.
https://www.apexofficeprint.com/docs/ 22/197
6/9/2019 APEX Office Print
If you want to print documents in batch, this page shows you three ways of doing it.
First one will generate one document with the pages in here. Second will generate multiple documents.
And last option will generate multiple documents but present it back as a zip file.
https://www.apexofficeprint.com/docs/ 23/197
6/9/2019 APEX Office Print
This page gives an overview and example of the different template and data types that are possible in the
APEX Office Print (AOP) Plug-in and API. The template type defines where your template is defined
(table, filesystem, URL, APEX, ...). The data type defines where the data can be found to be merged with
the template (SQL, PL/SQL, JSON, REST, ...).
This page gives an overview of the pages where and how the APEX Office Print (AOP) Plug-in is used.
https://www.apexofficeprint.com/docs/ 24/197
6/9/2019 APEX Office Print
You can automatically test all your documents in this screen and see if all of your defined templates and
data sources merged correctly. This option is especially useful after an upgrade of AOP or Office.
19. Templates
The idea here is that in your own application, you allow people to create or update their own templates
and upload them to the application without the need for developer to code other documents.
https://www.apexofficeprint.com/docs/ 25/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 26/197
6/9/2019 APEX Office Print
1. Start walks you step-by-step how you can get AOP working in your own application.
https://www.apexofficeprint.com/docs/ 27/197
6/9/2019 APEX Office Print
2. Tour shows the different techniques you can use and goes in more detail when to use which plug-in, the
PL/SQL API or do a manual REST request.
https://www.apexofficeprint.com/docs/ 28/197
6/9/2019 APEX Office Print
3. Examples shows different use cases of AOP, so you can see exactly behind the scenes how AOP is
used.
https://www.apexofficeprint.com/docs/ 29/197
6/9/2019 APEX Office Print
5. More is a link to our website where you find the release history, FAQ, Tutorials etc.
6. Support will open your default email client so you can write us.
https://www.apexofficeprint.com/docs/ 30/197
6/9/2019 APEX Office Print
1. Installation walks you step-by-step how you can get AOP working in your own application.
https://www.apexofficeprint.com/docs/ 31/197
6/9/2019 APEX Office Print
2. Architecture shows the flow of the different components and techniques you can use and goes in more
detail when to use which plug-in, the PL/SQL API or do a manual REST request.
https://www.apexofficeprint.com/docs/ 32/197
6/9/2019 APEX Office Print
3. APEX Features shows the integration of AOP with specific APEX features like Interactive Reports,
Interactive Grid and Calendar.
4. Examples shows different possibilities of AOP, so you can see exactly behind the scenes how AOP is
used.
5. Use Cases show different use cases people requested or had issues with (coming soon).
https://www.apexofficeprint.com/docs/ 33/197
6/9/2019 APEX Office Print
8. Support will open your default email client so you can write us.
3 APEX Plug-in
3.1 Pre-requisites
The APEX Office Print APEX plug-in requires Oracle APEX 5.0.4 or higher.
The AOP plug-ins are relying on a PL/SQL package (aop_api_pkg which is a synonym for
aop_api19_pkg) that needs to be compiled first.
To make the package available, go into SQL Plus, SQLcl, SQL Developer or SQL Workshop and run the SQL
Script aop_db_pkg.sql which you find in the db directory of the zip you downloaded.
Alternatively, you can run the install.sql file which will install some additional packages which show case how to
use AOP from PL/SQL.
If you imported the AOP Sample App and ran the Supporting Objects, the packages are automatically installed.
https://www.apexofficeprint.com/docs/ 34/197
6/9/2019 APEX Office Print
Follow these steps to finish your Plug-in installation by adding your Plug-in API key:
9. Click Apply
Installation note: To use AOP PL/SQL API you may need to configure your ACL (Access Control List) settings to
allow access to: http(s)://api.apexofficeprint.com
For more details please refer to Oracle APEX installation guide: for APEX 5.0
(https://docs.oracle.com/cd/E59726_01/install.50/e39144/listener.htm#HTMIG29160) or for APEX 5.1
(http://docs.oracle.com/database/apex-5.1/HTMIG/enabling-network-services-in-Oracledb-11g-or-
later.htm#HTMIG29160) or for APEX 18.1 (https://docs.oracle.com/database/apex-18.1/HTMIG/enabling-
network-services-in-Oracle-db11g-or-later.htm#HTMIG29161)
In case you want to update some plug-in settings, you find the plug-in settings in Shared Components >
Component Settings > APEX Office Print (AOP) [Plug-in]
https://www.apexofficeprint.com/docs/ 35/197
6/9/2019 APEX Office Print
You can change the AOP URL, AOP Failover URL (and Procedure which is being called on failover), API Key,
Debug and specify a package where those settings are specified. Since AOP 3.5 you can also specify a Log
package which will be called on every request, so you can monitor directly from your Oracle database if prints
are successful. If you use the on-premise version of AOP you can also change the Converter.
Since AOP 19.1 it's possible to change the AOP Mode to Development, which means you don't use any credits
in our AOP Cloud and have unlimited prints/reports (ignored by AOP On-Premises version). In AOP
Development Mode a text box (watermark) will be included at the top of the document.
To generate a PDF, APEX Office Print is using an external converter. By default, LibreOffice is used (available on
all platforms), but this can be changed to MS Office (Windows only). It is also possible to use a custom
converter. The custom conver needs to be defined inside the aop_config.json file. See section 8.1 for more
information.
https://www.apexofficeprint.com/docs/ 36/197
6/9/2019 APEX Office Print
1) Create a new button called PRINT and place it right of the RESET button.
2) Create a new process (APEX 5.0) or dynamic action (APEX 5.1) called AOP and select as type AOP [Plug-in]
3) Set the Data Type option of the plug-in to SQL and paste following select in the Data Source. Please note the
use of cursor data. The tags that you use in the template should be inside this data cursor.
https://www.apexofficeprint.com/docs/ 37/197
6/9/2019 APEX Office Print
```sql
select
'file1' as "filename",
cursor(
select
c.cust_first_name as "cust_first_name",
c.cust_last_name as "cust_last_name",
c.cust_city as "cust_city",
cursor(
select
o.order_total as "order_total",
'Order ' || rownum as "order_name",
cursor(
select
p.product_name as "product_name",
i.quantity as "quantity",
i.unit_price as "unit_price",
APEX_WEB_SERVICE.BLOB2CLOBBASE64(p.product_image) as "image"
from
demo_order_items i, demo_product_info p
where
o.order_id = i.order_id
and i.product_id = p.product_id
) "product"
from
demo_orders o
where
c.customer_id = o.customer_id
) "orders"
from
demo_customers c
where
customer_id = 1
) as "data"
from dual
```
5) Add as Condition for the process set only to run when button clicked PRINT.
When clicking on the Print button you should now get your first Word document. This document represents a
starting template based on your data. You'll see all tags that you can use and some more explanations how to
use expressions and certain features of AOP. You can now create your template in MS Word (or Excel or
PowerPoint) and use the tags in your template. Follow the next steps to do this.
7) Create your template in Word and use the tags that came in the first document you got.
8) Go to Shared Components > Static Application Files and upload your template
11) In Template Source enter your document you uploaded in step 8 e.g. my_template.docx
https://www.apexofficeprint.com/docs/ 38/197
6/9/2019 APEX Office Print
When clicking on the Print button you should now get your Word document based on your template with the tags
replaced by the data coming from the database.
In subsections to follow you can find more details for each of them.
Use static files kept on a server or as Application/Workspace files (acting as as global templates)
AOP Template
Will generate a Word document with a starting template based on the data (JSON) that is submitted.
Will reference files you find in Shared Components > Static Application Files
Will reference files you find in Shared Components > Static Workspace Files
SQL
Query that returns two columns: template_type and file (in this order)
https://www.apexofficeprint.com/docs/ 39/197
6/9/2019 APEX Office Print
{
"file":"clob base64 data",
"template_type":"docx,xlsx,pptx,html,md,txt,csv,ics"
}
Enter the path and filename of the template which is stored on the same server AOP is running at.
Enter the URL to your template in docx, xlsx, pptx, html, md, txt, ics, or csv. e.g.
https://www.apexofficeprint.com/templates/aop_template_d01.docx Always make sure your URL ends with the
filename. E.g. for Google Drive add to the end of the URL &aop=.docx This call is done from the database, so
the database server needs to have access to the URL.
Enter the URL to your template in docx, xlsx, pptx, html, md, txt, ics, or csv. e.g.
https://www.apexofficeprint.com/templates/aop_template_d01.docx Always make sure your URL ends with the
filename. E.g. for Google Drive add to the end of the URL &aop=.docx This call is done from AOP, so the AOP
server needs to have access to the URL.
aop_simple_letter.docx
aop_simple_letter.docx
SQL
https://www.apexofficeprint.com/docs/ 40/197
6/9/2019 APEX Office Print
select
a.TEMPLATE_TYPE as template_type,
apex_web_service.blob2clobbase64(a.TEMPLATE_BLOB) as file
from aop_template a
where id = 1
declare
l_return clob;
begin
l_return := q'[
select
a.TEMPLATE_TYPE as template_type,
apex_web_service.blob2clobbase64(a.TEMPLATE_BLOB) as file
from aop_template a
where id = 1
]';
return l_return;
end;
declare
l_return clob;
begin
l_return := '{ "file": "", "template_type": "docx" }';
return l_return;
end;
declare
l_return clob;
l_template clob;
l_template_type aop_template.template_type%type;
begin
select template_type, apex_web_service.blob2clobbase64(template_blob) template
into l_template_type, l_template
from aop_template
where id = :p4_template;
You can use this technique to load html as template. Please have a look at page 114 of the sample application.
aop_template.docx
Note: Filename supports Substitutions like Application Items, Page Items and System Variables
https://www.apexofficeprint.com/docs/ 41/197
6/9/2019 APEX Office Print
http://apexofficeprint.com/templates/aop_template_d01.docx
SQL
Select statement in which you can use cursor to do nested records. Use "" as alias column names to force lower
case column names. The data you select should be inside the data cursor. AOP plug-in expects two columns:
filename and data.
select
'file1' as "filename",
cursor
(
***Your select statement***
) as "data"
from dual
Source should point to URL that returns JSON object with following format: { "filename": "file1", "data":[{...}] } If
the URL is using an APEX ORDS REST call it will automatically be wrapped with additional JSON: {"items":[...]}
All of this will be handled for you by AOP Plug-in.
Region(s): Classic and/or Interactive Report(s) and/or Interactive Grid(s) and/or Charts
One or more classic and/or interactive reports and/or interactive grids will be used as the source for your data.
The Dynamic Action plug-in also has the possibility to take a screenshot of for example a JET chart or any other
div (svg/canvas).
Note that you can use bind variables like :PX_ITEM as well in your SQL-statement. You find examples when you
click on Help in the APEX Plug-in when you're on the Data Source field
SQL
https://www.apexofficeprint.com/docs/ 42/197
6/9/2019 APEX Office Print
select
'file1' as "filename",
cursor(
select
c.cust_first_name as "cust_first_name",
c.cust_last_name as "cust_last_name",
c.cust_city as "cust_city",
cursor(
select
o.order_total as "order_total",
'Order ' || rownum as "order_name",
cursor(
select
p.product_name as "product_name",
i.quantity as "quantity",
i.unit_price as "unit_price",
APEX_WEB_SERVICE.BLOB2CLOBBASE64(p.product_image) as "image"
from
demo_order_items i, demo_product_info p
where
o.order_id = i.order_id
and i.product_id = p.product_id
) "product"
from
demo_orders o
where
c.customer_id = o.customer_id
) "orders"
from
demo_customers c
where
customer_id = :P4_CUSTOMER_ID
) as "data"
from dual
Be sure to put the the returned data inside the data cursor.
select
'file1' as "filename",
cursor(
***Your Select Statement***
)
as "data"
from dual
The returned SQL should contain the data inside data cursor like above.
https://www.apexofficeprint.com/docs/ 43/197
6/9/2019 APEX Office Print
declare
l_return clob;
begin
l_return := q'[
select
'file1' as "filename",
cursor(
select
c.cust_first_name as "cust_first_name",
c.cust_last_name as "cust_last_name",
c.cust_city as "cust_city",
cursor(
select
o.order_total as "order_total",
'Order ' || rownum as "order_name",
cursor(
select
p.product_name as "product_name",
i.quantity as "quantity",
i.unit_price as "unit_price",
APEX_WEB_SERVICE.BLOB2CLOBBASE64(p.product_image) as "image"
from
demo_order_items i, demo_product_info p
where
o.order_id = i.order_id
and i.product_id = p.product_id
) "product"
from
demo_orders o
where
c.customer_id = o.customer_id
) "orders"
from
demo_customers c
where
customer_id = :P4_CUSTOMER_ID
) as "data"
from dual
]';
return l_return;
end;
Note how the JSON contains the data object with the actual data inside it.
https://www.apexofficeprint.com/docs/ 44/197
6/9/2019 APEX Office Print
declare
l_cursor sys_refcursor;
l_return clob;
begin
apex_json.initialize_clob_output(dbms_lob.call, true, 2) ;
open l_cursor for
select 'file1' as "filename",
cursor
(select
c.cust_first_name as "cust_first_name",
c.cust_last_name as "cust_last_name" ,
c.cust_city as "cust_city" ,
cursor
(select
o.order_total as "order_total",
'Order ' || rownum as "order_name" ,
cursor
(select
p.product_name as "product_name",
i.quantity as "quantity" ,
i.unit_price as "unit_price" ,
apex_web_service.blob2clobbase64(p.product_image) as "image"
from
demo_order_items i,
demo_product_info p
where
o.order_id = i.order_id
and i.product_id = p.product_id
) "product"
from
demo_orders o
where
c.customer_id = o.customer_id
and rownum < 2
)"orders"
from
demo_customers c
where
customer_id = :P4_CUSTOMER_ID
) as "data"
from dual;
apex_json.write(l_cursor);
l_return := apex_json.get_clob_output;
return l_return;
end;
For this you need to create a new Webservice following these steps:
Click Create button and follow the wizard. For RESTful Services Module set
https://www.apexofficeprint.com/docs/ 45/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 46/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 47/197
6/9/2019 APEX Office Print
select
file1' as "filename",
cursor(
select
c.cust_first_name,
c.cust_last_name,
c.cust_city,
cursor(
select
o.order_total,
'Order ' || rownum as order_name,
cursor(
select
p.product_name,
i.quantity,
i.unit_price,
APEX_WEB_SERVICE.BLOB2CLOBBASE64(p.product_image) as image
from
demo_order_items i,
demo_product_info p
where
o.order_id = i.order_id
and i.product_id = p.product_id
) product
from
demo_orders o
where
c.customer_id = o.customer_id
and rownum < 2
) orders
from
demo_customers c
where
customer_id = :id
) as "data"
from dual
Note: For Resource Handler: GET setting after you created your RESTful service you may need to change
Requires Secure Access setting from default Yes to No.
not defined in Data Source but in Region Static ID(s) (see 3.5.5)
3.5.6 Special
https://www.apexofficeprint.com/docs/ 48/197
6/9/2019 APEX Office Print
Specific features of APEX Office Print which become available when the data type is SQL or Classic and/or
Interactive Report(s)
Treat all numbers as strings There's a limitation in APEX with the cursor() statement in SQL that it doesn't
remember which datatype the column is in. So when doing to_char(0.9,'990D00') it will return 0.9 as number
instead of as string '0.90'. To resolve this, enable this checkbox and concatenate your number with '!FMT!' e.g.
'!FMT!'||to_char(35, '990D00') - !FMT! stands for format.
Alternatively if you format your number with the currency sign to_char(35,'FML990D00') Oracle will recognise it
as a string and you don't need to use this checkbox.
Report as Labels Check this box in case you want to use the Classic or Interactive Report data source but print
them as Labels (using the Mailings feature in Word). * this option is deprecated since AOP 3.0 as AOP
understands labels depending the template.
IR/IG: Show Filters on top When there're filters applied to the Interactive Report/Grid, this checkbox will print
them above the report.
IR/IG: Show Highlights on top When there're highlights applied to the Interactive Report/Grid, this checkbox
will print them above the report.
IR/IG: Show header with filter (Excel) When checked AOP will make the header of the Interactive Report/Grid
in Excel a filter.
IR/IG: Use Saved Report instead of Report in Session If you want to make sure you always call a specific
Interactive Report/Grid, without taking into account what the person is doing with it, you can check this box and
the named (saved) Interactive Report will be taken. e.g. ir1|my_saved_report would be in your source.
IR/IG: Repeat header on every page When the table spans multiple pages, the header row will be repeated on
every page.
Filename examples
Static: my_file
aop_api_pkg.g_output_filename := 'output';
aop_api_pkg.g_output_filename := v('P1_FILENAME');
aop_api_pkg.g_rpt_header_font_size := '12';
https://www.apexofficeprint.com/docs/ 49/197
6/9/2019 APEX Office Print
Word (docx)
Excel (xlsx)
PowerPoint (pptx)
PDF (pdf)
HTML (html)
Markdown (md)
Comma/Column Separated Values (CSV)
Word (rtf)
Defined by APEX Item
3.5.10 Output To
Available options include:
Browser
Procedure
This option will call a procedure in a specific format e.g. send_email_prc. This option is useful in case you do not
need the file on your own hard drive, but for example you want to mail the document automatically. In that case
you can create a procedure that adds the generated document as an attachment to your apex_mail.send.
procedure send_email_prc(
p_output_blob in blob,
p_output_filename in varchar2,
p_output_mime_type in varchar2)
This option allows you to call a procedure first and next download the file to your hard drive. An example is when
you first want to store the generated document in a table before letting the browser to download it.
If you want to output a PDF in a certain region or as a pop-up modal dialog, use this option. See section: 2.3.1.9
for more info. Please note that feature is not available on IE. You can use the modal page options instead.
Save the file to a directory specified with g_output_directory. The default directory on the AOP Server is
outputfiles. If you point this to a directory on a shared server or to a directory known by Google Drive or
Dropbox, you can easily generate and share documents. Note that the AOP server should enable this option by
using the --enable_save argument. It goes without saying that this option is not available while using cloud
subscription.
https://www.apexofficeprint.com/docs/ 50/197
6/9/2019 APEX Office Print
4 PL/SQL API
4.1 Pre-requisites
APEX 5.0.4 or higher needs to be installed in the database as the PL/SQL API uses some packages that come
with APEX e.g. apex_json
Next to the above two packages we also provide two additional packages that show how to do the pl/sql calls.
See the packages aop_sample_pkg and aop_test_pkg.
4.4 Parameters
aop_api_pkg
https://www.apexofficeprint.com/docs/ 51/197
6/9/2019 APEX Office Print
-- Logger
g_logger_enabled boolean := true; -- In case you use Logger (https://github.com/OraOp
-- SQL> ALTER PACKAGE aop_api19_pkg COMPILE PLSQL_C
-- When compiled and this global variable is set to
-- Call to AOP
g_aop_url varchar2(100) := null; -- AOP Server URL
g_api_key varchar2(50) := null; -- AOP API Key; only needed when AOP Cloud is used
g_aop_mode varchar2(15) := null; -- AOP Mode can be development or production; when
g_failover_aop_url varchar2(100) := null; -- AOP Server URL in case of failure of AOP URL
g_failover_procedure varchar2(200) := null; -- When the failover URL is used, the procedure spe
g_output_converter varchar2(50) := null; -- Set the converter to go to PDF (or other format
g_proxy_override varchar2(300) := null; -- null=proxy defined in the application attributes
g_transfer_timeout number(6) := 1800; -- default of APEX is 180
g_wallet_path varchar2(300) := null; -- null=defined in Manage Instance > Instance Setti
g_wallet_pwd varchar2(300) := null; -- null=defined in Manage Instance > Instance Setti
g_output_filename varchar2(300) := null; -- output
g_cloud_provider varchar2(30) := null; -- dropbox, gdrive, onedrive, aws_s3
g_cloud_location varchar2(300) := null; -- directory in dropbox, gdrive, onedrive, aws_s3 (
g_cloud_access_token varchar2(500) := null; -- access token for dropbox, gdrive, onedrive, aws_
g_language varchar2(2) := c_en; -- Language can be: en, fr, nl, de, used for the tr
g_app_language varchar2(20) := null; -- Language specified in the APEX app (primary lang
g_logging clob := ''; -- ability to add your own logging: e.g. "request_i
g_debug varchar2(10) := null; -- set to 'Local' when only the JSON needs to be ge
g_debug_procedure varchar2(4000):= null; -- when debug in APEX is turned on, next to the nor
-- e.g. to write to your own debug table. The def
-- APEX Page Items
g_apex_items varchar2(4000):= null; -- colon separated list of APEX items e.g. P1_X:P1_
-- Layout for IR
g_rpt_header_font_name varchar2(50) := ''; -- Arial - see https://www.microsoft.com/typography
g_rpt_header_font_size varchar2(3) := ''; -- 14
g_rpt_header_font_color varchar2(50) := ''; -- #071626
g_rpt_header_back_color varchar2(50) := ''; -- #FAFAFA
g_rpt_header_border_width varchar2(50) := ''; -- 1 ; '0' = no border
g_rpt_header_border_color varchar2(50) := ''; -- #000000
g_rpt_data_font_name varchar2(50) := ''; -- Arial - see https://www.microsoft.com/typography
g_rpt_data_font_size varchar2(3) := ''; -- 14
g_rpt_data_font_color varchar2(50) := ''; -- #000000
g_rpt_data_back_color varchar2(50) := ''; -- #FFFFFF
g_rpt_data_border_width varchar2(50) := ''; -- 1 ; '0' = no border
g_rpt_data_border_color varchar2(50) := ''; -- #000000
g_rpt_data_alt_row_color varchar2(50) := ''; -- #FFFFFF for no alt row color, use same color as
/* see also Printing attributes in Interactive Report */
-- Settings for Calendar
g_cal_type varchar2(10) := c_cal_month; -- can be month (default), week, day, list; c
g_start_date date := null; -- start date of calendar
g_end_date date := null; -- end date of calendar
g_weekdays varchar2(300) := null; -- translation for weekdays e.g. Monday:Tuesday:W
g_months varchar2(300) := null; -- translation for months e.g. January:February
g_color_days_sql varchar2(4000):= null; -- color the background of certain days.
-- e.g. select 1 as "id", sysdate as "date", 'FF8
-- HTML template to Word/PDF
g_orientation varchar2(50) := ''; -- empty is portrait, other option is 'landscape'
-- Call to URL data source
g_url_username varchar2(300) := null;
g_url_password varchar2(300) := null;
g_url_proxy_override varchar2(300) := null;
https://www.apexofficeprint.com/docs/ 52/197
6/9/2019 APEX Office Print
-- Files
g_prepend_files_sql clob := null; -- format: select filename, mime_type, [file_blob, file_ba
g_append_files_sql clob := null; -- from my_table
-- Sub-Templates
g_sub_templates_sql clob := null; -- format: select filename, mime_type, [file_blob, file_ba
Function call
https://www.apexofficeprint.com/docs/ 53/197
6/9/2019 APEX Office Print
function plsql_call_to_aop(
p_data_type in varchar2 default c_source_type_sql,
p_data_source in clob,
p_template_type in varchar2 default c_source_type_apex,
p_template_source in clob,
p_output_type in varchar2,
p_output_filename in out nocopy varchar2,
p_output_type_item_name in varchar2 default null,
p_output_to in varchar2 default null,
p_procedure in varchar2 default null,
p_binds in wwv_flow_plugin_util.t_bind_list default c_binds,
p_special in varchar2 default null,
p_aop_remote_debug in varchar2 default c_no,
p_output_converter in varchar2 default null,
p_aop_url in varchar2,
p_api_key in varchar2 default null,
p_aop_mode in varchar2 default null,
p_app_id in number default null,
p_page_id in number default null,
p_user_name in varchar2 default null,
p_init_code in clob default c_init_null,
p_output_encoding in varchar2 default c_output_encoding_raw,
p_output_split in varchar2 default c_false,
p_output_even_page in varchar2 default c_false,
p_output_merge_making_even in varchar2 default c_false,
p_failover_aop_url in varchar2 default null,
p_failover_procedure in varchar2 default null,
p_log_procedure in varchar2 default null,
p_prepend_files_sql in clob default null,
p_append_files_sql in clob default null,
p_sub_templates_sql in clob default null)
return blob;
Note that some other procedures and functions are available in the package which could be helpful.
aop_plsql_pkg
function make_aop_request(
p_aop_url in varchar2 default g_aop_url,
p_api_key in varchar2 default g_api_key,
p_json in clob,
p_template in blob,
p_output_encoding in varchar2 default 'raw', -- change to raw to have binary, change to base64 to ha
p_output_type in varchar2 default null,
p_output_filename in varchar2 default 'output',
p_aop_remote_debug in varchar2 default 'No')
return blob;
4.5 Example
Example with aop_api_pkg
https://www.apexofficeprint.com/docs/ 54/197
6/9/2019 APEX Office Print
declare
l_binds wwv_flow_plugin_util.t_bind_list;
l_return blob;
l_output_filename varchar2(100) := 'output';
begin
-- define bind variables
l_binds(1).name := 'p_id';
l_binds(1).value := '1';
l_return := aop_api_pkg.plsql_call_to_aop (
p_data_type => 'SQL',
p_data_source => q'[
select
'file1' as "filename",
cursor(
select
c.cust_first_name as "cust_first_name",
c.cust_last_name as "cust_last_name",
c.cust_city as "cust_city",
cursor(select o.order_total as "order_total",
'Order ' || rownum as "order_name",
cursor(select p.product_name as "product_name",
i.quantity as "quantity",
i.unit_price as "unit_price", APEX_WEB_SERVICE.BLOB2CLO
from demo_order_items i, demo_product_info p
where o.order_id = i.order_id
and i.product_id = p.product_id
) "product"
from demo_orders o
where c.customer_id = o.customer_id
) "orders"
from demo_customers c
where customer_id = :p_id
) as "data"
from dual
]',
p_template_type => 'SQL',
p_template_source => q'[
select template_type, template_blob
from aop_template
where id = 1
]',
p_output_type => 'docx',
p_output_filename => l_output_filename,
p_binds => l_binds,
p_aop_url => 'http://api.apexofficeprint.com/',
p_api_key => 'your API key',
p_app_id => 232);
end;
https://www.apexofficeprint.com/docs/ 55/197
6/9/2019 APEX Office Print
declare
l_template blob;
l_output_file blob;
begin
select template_blob
into l_template
from aop_template
where id = 1;
l_output_file := aop_plsql_pkg.make_aop_request(
p_json => '[{ "filename": "file1", "data": [{ "cust_first_name": "APEX Offi
p_template => l_template,
p_output_type => 'docx',
p_aop_remote_debug => 'Yes');
end;
In aop_sample_pkg you find the above examples and you can run them with following command:
begin
aop_sample_pkg.call_aop_plsql_pkg;
aop_sample_pkg.call_aop_api_pkg;
end;
Note that there are more examples in the aop_sample_pkg, so it's worthwhile to check it out.
This JSON file contains an JSON object meaning it starts with { and ends with }. This JSON object contains four
compulsory JSON objects namely "template", "output", "files", "api_key" and a few optional object "version",
"logging", "apex_version", "aop_remote_debug" and "ipp". The purpose of each object will now be explained.
https://www.apexofficeprint.com/docs/ 56/197
6/9/2019 APEX Office Print
This object contains the version of AOP JSON format used. The current version is 18.2 and backwards
compatible thus optional. This will be used for future upgrades and if the newer version is not backwards
compatible.
JSON Explanation
"filename" This option is for on-premise users. The template defined by this object will be
used for processing. Note that the filename either contains a relative path from
where the server is running from (or the folder/directory containing application) or
an absolute path.
"url" This option allows you to give the URL containing the template. The URL will also
work with google drive (also with google docs/slides/powerpoint) and dropbox file
sharing link. However this might not work in the future since the way links work
might be changed by google or dropbox. Note this URL can also use ftp protocol.
"template_type" This states what kind of template is being used. It must be either "docx", "pptx",
"xlsx", "html" or "md".
"html_template_content" Since AOP 3.4 it is possible to just pass html as template. This is equivalent as
using {_html} tag in word to create the template which is then again passed to the
AOP with the data for rendering.
"orientation" nothing or "landscape". If landscape is provided then the html template content will
be rendered in a landscape A4 word template. Taken only into account when
html_template_content is provided.
If "file","filename" or "url" objects are not present in the "template" object then the server will respond with a
custom template file of "template_type" made from this given JSON file. Currently only Word, Excel and
PowerPoint template generation is supported.
The sharing link made by dropbox and google drive will be modified to that the online editor will not be triggered,
and are subject to change by google drive and dropbox. For this reason using share link for production is
discouraged. The change happens in the following way:
https://www.apexofficeprint.com/docs/ 57/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 58/197
6/9/2019 APEX Office Print
JSON Explanation
"output_type" This states what kind of output file type is required. It can be either the
same as template_type ("docx", "pptx", "xlsx", "html", "md"), "pdf" or any
other output file supported by libreoffice/openoffice. Special output type:
"onepagepdf", this will cause the ouptut to be converted to pdf and all
the pages will be merged into one single page. Default: the same as
template_type.
"output_encoding" This states what kind of output encoding is wished for the output file. It
must be either "raw" or "base64".
"output_converter" This states which software should be used to convert to pdf. The
ApexOfficePrint server usages LibreOffice. On premise users may use
MS Office but will need to do some configuration first. Available values:
"officetopdf" (Windows only) or "libreoffice" (Windows, Linux, OSX) or
any other custom defined converters in aop_config.json file (see setting
up AOP) if you are using On Premise Version.
"output_directory" If save on disk is enabled, then the document will be saved on the path
resulted by combining this given path with the specified directory.
"output_even_page" If you want your output to have even pages, for example printing on
both sides after merging, you can set this to be true. This option is only
available when the output is pdf. Optional.
"output_merge_making_even" Merge each given document making even paged. This option is only
available when the output is pdf. Optional.
"output_modify_password" Requires output pdf, the password needed to modify the pdf. Optional.
Read password, if given, will be used if this field is empty.
"output_read_password" Requires output pdf, the password needed to open the pdf. Optional.
"output_password_protection_flag" Requires output pdf, bit field explained in the PDF specs in table 3.20 in
section 3.5.2, should be given in decimal more info
(http://pdfhummus.com/post/147451287581/hummus-1058-and-pdf-
writer-updates-encryption). Optional. Default (4).
"lock_form" Requires output pdf, locks/flattens the forms in the pdf. Optional.
https://www.apexofficeprint.com/docs/ 59/197
6/9/2019 APEX Office Print
5.2.4 "api_key"
The value of this key is the API key given by ApexOfficePrint. Only applicable for service users.
https://www.apexofficeprint.com/docs/ 60/197
6/9/2019 APEX Office Print
This array contains the data that will be used for the given template. If this array contains more than one object
then the output files, which are generated using the same template for each item, will be returned in a zip file.
This array contains JSON objects with following fields:
JSON Explanation
"data" This array (containing one object) or object contains the data that will be replaced in the
template.
Example showing a basic JSON file which should be populated with data:
{
"template": {
"filename" :"template.docx",
"template_type" :"docx"
},
"output": {
"output_encoding" :"raw",
"output_type" :"docx",
"output_directory" :"."
},
"files": [{
"filename" :"file1",
"data" : [{...}]
}]
}
For example:
"logging": {
"template_filename": "AOP template",
"output_filename": "output.docx"
}
https://www.apexofficeprint.com/docs/ 61/197
6/9/2019 APEX Office Print
"ipp": {
"location": "http://10.0.14.223:631/",
"version": "1.1",
"requester": "YOUR NAME",
"job_name": "AOP"
}
"post_process":{
"command":"echo", //The command to execute. This command should be present on aop_config.json file
"return_output":true, //Either to return the output or not. Note this output is AOP's output and no
"delete_delay": 1500 // AOP deletes the file provided to the command directly after executing it. T
6 Templates
The templates are standard office files in which tags will be replaced by structured data from the JSON file.
These tags are quite standardized for either .docx, .pptx or .xlsx, however there are some subtle differences.
They are all able to handle JavaScript angular expressions, on which some of the basics will follow.
https://www.apexofficeprint.com/docs/ 62/197
6/9/2019 APEX Office Print
{:inline_data_loop} … No No No No No No Yes
{/inline_data_loop}
Note: tags can't start with a number and should start with an alphabetical character (a-z,A-Z)
Special Tags:
{current_child_index}: Will resolve to current index of the record array, starting from 0.
{#object|keys}{.}{/object|keys}: Will iterate over the names of the keys from the given object. If it's
https://www.apexofficeprint.com/docs/ 63/197
6/9/2019 APEX Office Print
This tag, {data_string}, will be replaced by the value of the key "data_string" in the JSON file.
{
"template": {
"filename" :"template.docx",
"template_type" :"docx"
},
"output": {
"output_encoding" :"raw",
"output_type" :"docx"
},
"files": [{
"filename" :"output",
"data": [{
"first_name" :"DemoName",
"last_name" :"DemoLastName",
"city" :"DemoCity"
}]
}]
}
{last_name} {first_name}
{city}
DemoLastName DemoName
DemoCity
Since the template and the output objects from the json will not change, these will be omitted from the examples
given below.
https://www.apexofficeprint.com/docs/ 64/197
6/9/2019 APEX Office Print
{
...
"files":[{
"filename" :"output",
"data":[{
"product_name" :"Wallet",
"price" :"$500.00",
"pic" :"/...code..../",
"pic_max_width" : 100,
"pic_max_height" : 100
}]
}]
}
with template:
https://www.apexofficeprint.com/docs/ 65/197
6/9/2019 APEX Office Print
Tip: in case you want to make your images equal in size, you can use PL/SQL to resize your images. Here's an
example to put the size of the image to a maximum of 200px.
declare
l_img blob;
begin
select image
into l_img
from my_table
where id = 1 for update;
ordsys.ordimage.process(l_img, 'maxscale=200 200');
update my_table
set image = l_img
where id = 1;
end;
https://www.apexofficeprint.com/docs/ 66/197
6/9/2019 APEX Office Print
1. key_type, e.g. "barcode_type" if the key used is "barcode". This field contains the type of barcode
required. The options are: codabar
code128
code128a
code128b
code128c
code39
ean13
ean2
ean5
ean8
itf
itf14
msi
msi10
msi1010
msi11
msi1110
pharmacode
upc
upce
2. key_height, e.g. "barcode_height" if the key used is "barcode". This field contains the height for the
generated image. Default is 200 for QR, 50 for the rest.
3. key_width, e.g. "barcode_width" if they key used is "barcode". This field contains the width for the
generated image. Default is 200.
4. key_errorcorrectlevel (only for QR code), e.g. "qrcode_errorcorrectlevel" if the key used is "qrcode". This
field contains the level of which the QR code should be recoverable. The options are: "L" (up to 7%
damage) "M" (up to 15% damage) "Q" (up to 25% damage) "H" (up to 30% damage) Extra info:
http://www.qrcode.com/en/about/error_correction.html
(http://www.qrcode.com/en/about/error_correction.html)
5. key_cellsize (only for QR code), e.g. "qrcode_cellsize". This field contains the dot size of a module.
Default is 4. Extra info: http://www.qrcode.com/en/howto/cell.html
(http://www.qrcode.com/en/howto/cell.html)
https://www.apexofficeprint.com/docs/ 67/197
6/9/2019 APEX Office Print
{
...
"files":[{
"filename" :"output",
"data":[{
"product_name" :"Wallet",
"product_code" :"1896547832148",
"product_code_type" :"ean13",
"product_link" :"https://www.google.be/search?q=wallet",
"product_link_type" :"qrcode"
}]
}]
}
https://www.apexofficeprint.com/docs/ 68/197
6/9/2019 APEX Office Print
For barcodes, instead of doing the above, you could also choose to install a barcode font, for example Free 3of9
(https://www.barcodesinc.com/free-barcode-font/) or http://www.dafont.com/3of9-barcode.font
(http://www.dafont.com/3of9-barcode.font). Barcode fonts are more performant than images. See the other
section for more information about language and font support.
https://www.apexofficeprint.com/docs/ 69/197
6/9/2019 APEX Office Print
defaultOptions = {
width: 5486400 / 9525, // width of the chart
height: 3200400 / 9525, // height of the chart
grid: true, // if a grid should be shown
border: true, // if a border should be shown
title: false,
legend: {
showLegend: true, // if the legend should be shown
position: 'r' // 'l' for left, 'r' right, 'b' bottom, 't' top
},
dataLabels: { //Available only after AOP 19.1
showDataLabels: false, // can be true or false, default true for pie/pie3d and doughnut
seperator: false, // can be either false or anything else for example \n or \t or ; or
showSeriesName: false, // include the series name in the data label, true or false
showCategoryName: false, // include the series category name in the data label, true or
showLegendKey: false, // include the legend key (i.e the color of the series) in the
showValue: false, // include the actual value in the data label
showPercentage: false, // include the percentage, default true for pie/pie3d and doughn
position: 'center' // position to show the data label, can be 'center', 'left', 'right'
},
axis: {
x: {
orientation: 'minMax', // or "maxMin"
min: undefined, // a specific number
max: undefined, // a specific number
type: undefined, // or "date"
date: { //date options
format: 'unix',
code: 'mm/yy',
unit: 'months',
step: '1'
},
title:'title for x axis', //From 19.1.1
showValues: true //options to disable showing the values in axis
},
y: {
orientation: 'minMax',
mix: undefined,
max: undefined,
title: 'Title for y axis', //From 19.1.1
showValues: true // options to disable showing the values in axis
},
y2: { //If using multiple charts and axis on the right side
orientation: 'minMax',
mix: undefined,
max: undefined,
title: 'Title for y2 axis', //From 19.1.1
showValues: true // options to disable showing the values in axis
}
}
}
https://www.apexofficeprint.com/docs/ 70/197
6/9/2019 APEX Office Print
Secondly the type of chart should be determined by "type" key. The generation of following types of charts is
supported:
6.1.4.1 Line
This is a normal chart where the data's are connected with lines. Multiple lines can be generated. The chart key
should contain lines array inside with the data of the lines that should be generated and the name of the line.
E.g.:
"chart": {
"lines": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "line 1",
"smooth": true, //Can be false
"symbol": "square" // can be diamond triangle
},
{
"data": [
{
"x": "day 1",
"y": "2.4"
},
{
"x": "day 2",
"y": "4.4"
},
{
"x": "day 3",
"y": "1.8"
}
],
"name": "line 2"
}
],
"type": "line"
}
will result in :
https://www.apexofficeprint.com/docs/ 71/197
6/9/2019 APEX Office Print
6.1.4.2 bar
In order to generate the bar chart, the chart object should contain array named bars. This array contains the
objects with data about the bar and the name of the bar. For example, given the following:
https://www.apexofficeprint.com/docs/ 72/197
6/9/2019 APEX Office Print
...
"chart": {
"bars": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "bar 1"
},
{
"data": [
{
"x": "day 1",
"y": "2.4"
},
{
"x": "day 2",
"y": "4.4"
},
{
"x": "day 3",
"y": "1.8"
}
],
"name": "bar 2"
}
],
"type": "bar"
}
...
https://www.apexofficeprint.com/docs/ 73/197
6/9/2019 APEX Office Print
...
"chart": {
"bars": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "bar 1"
}
],
"type": "bar"
}
...
https://www.apexofficeprint.com/docs/ 74/197
6/9/2019 APEX Office Print
6.1.4.3 barStacked
This is similar to bar chart but the bars from same category will be stacked. For example, given the following:
https://www.apexofficeprint.com/docs/ 75/197
6/9/2019 APEX Office Print
...
"chart": {
"bars": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "bar 1"
},
{
"data": [
{
"x": "day 1",
"y": "2.4"
},
{
"x": "day 2",
"y": "4.4"
},
{
"x": "day 3",
"y": "1.8"
}
],
"name": "bar 2"
}
],
"type": "barStacked"
}
...
https://www.apexofficeprint.com/docs/ 76/197
6/9/2019 APEX Office Print
6.1.4.4 barStackedPercent
This is similar to bar stacked chart, but the x axis will be in expressed in percentage. For example, given the
following:
https://www.apexofficeprint.com/docs/ 77/197
6/9/2019 APEX Office Print
...
"chart": {
"bars": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "bar 1"
},
{
"data": [
{
"x": "day 1",
"y": "2.4"
},
{
"x": "day 2",
"y": "4.4"
},
{
"x": "day 3",
"y": "1.8"
}
],
"name": "bar 2"
}
],
"type": "barStacked"
}
...
https://www.apexofficeprint.com/docs/ 78/197
6/9/2019 APEX Office Print
6.1.4.5 column
This will produce a normal column chart. The chart object should contain an array named columns with objects
containing the data and name of the column. E.g.:
https://www.apexofficeprint.com/docs/ 79/197
6/9/2019 APEX Office Print
"chart": {
"columns": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "column 1"
},
{
"data": [
{
"x": "day 1",
"y": "2.4"
},
{
"x": "day 2",
"y": "4.4"
},
{
"x": "day 3",
"y": "1.8"
}
],
"name": "column 2"
}
],
"type": "column"
}
https://www.apexofficeprint.com/docs/ 80/197
6/9/2019 APEX Office Print
"chart": {
"columns": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "column 1"
}
],
"type": "column"
}
https://www.apexofficeprint.com/docs/ 81/197
6/9/2019 APEX Office Print
6.1.4.6 columnStacked
This will produce a column stacked chart. The chart object should contain an array named columns with objects
containing the data and the name of the column. E.g:
https://www.apexofficeprint.com/docs/ 82/197
6/9/2019 APEX Office Print
"chart": {
"columns": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "column 1"
},
{
"data": [
{
"x": "day 1",
"y": "2.4"
},
{
"x": "day 2",
"y": "4.4"
},
{
"x": "day 3",
"y": "1.8"
}
],
"name": "column 2"
}
],
"type": "columnStacked"
}
https://www.apexofficeprint.com/docs/ 83/197
6/9/2019 APEX Office Print
6.1.4.7 columnStackedPercent
This will produce a column stacked percent chart. The chart object should contain an array named columns with
objects containing the data and the name of the column. E.g:
https://www.apexofficeprint.com/docs/ 84/197
6/9/2019 APEX Office Print
"chart": {
"columns": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "column 1"
},
{
"data": [
{
"x": "day 1",
"y": "2.4"
},
{
"x": "day 2",
"y": "4.4"
},
{
"x": "day 3",
"y": "1.8"
}
],
"name": "column 2"
}
],
"type": "columnStackedPercent"
}
https://www.apexofficeprint.com/docs/ 85/197
6/9/2019 APEX Office Print
6.1.4.8 pie
This will produce a pie chart. The chart object should contain an array named pies with one element containing
the data and name of the pie chart. E.g:
https://www.apexofficeprint.com/docs/ 86/197
6/9/2019 APEX Office Print
"chart": {
"pies": [
{
"data": [
{
"x": "Order 1",
"y": 1890
},
{
"x": "Order 2",
"y": 2380
},
{
"x": "Order 3",
"y": 1640
},
{
"x": "Order 4",
"y": 1090
},
{
"x": "Order 5",
"y": 950
},
{
"x": "Order 6",
"y": 1515
},
{
"x": "Order 7",
"y": 905
},
{
"x": "Order 8",
"y": 1060
},
{
"x": "Order 9",
"y": 730
},
{
"x": "Order 10",
"y": 870
}
],
"name": "pie 1"
}
],
"type": "pie"
}
https://www.apexofficeprint.com/docs/ 87/197
6/9/2019 APEX Office Print
6.1.4.9 radar
This will produce a radar chart. The chart object should contain an array named radars with one element
containing the data and name of the radar chart. E.g:
https://www.apexofficeprint.com/docs/ 88/197
6/9/2019 APEX Office Print
"chart": {
"radars": [
{
"data": [
{
"x": "Order 1",
"y": 1240
},
{
"x": "Order 2",
"y": 380
},
{
"x": "Order 3",
"y": 840
},
{
"x": "Order 4",
"y": 490
},
{
"x": "Order 5",
"y": 1230
}
],
"name": "radar 1"
}
],
"type": "radar"
}
https://www.apexofficeprint.com/docs/ 89/197
6/9/2019 APEX Office Print
6.1.4.10 area
This will produce an area chart. The chart object should contain an array named areas with one element
containing the data and name of the area chart. E.g:
https://www.apexofficeprint.com/docs/ 90/197
6/9/2019 APEX Office Print
"chart": {
"areas": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "area 1"
},
{
"data": [
{
"x": "day 1",
"y": "2.4"
},
{
"x": "day 2",
"y": "4.4"
},
{
"x": "day 3",
"y": "1.8"
}
],
"name": "area 2"
}
],
"type": "area"
}
https://www.apexofficeprint.com/docs/ 91/197
6/9/2019 APEX Office Print
6.1.4.11 scatter
This will produce a scatter chart. The chart object should contain an array named scatters with one element
containing the data and name of the scatter chart. Similar to previous charts however the x axis should contain
only numbers.
6.1.4.13 bubble
This will produce a bubble chart. The chart object should contain an array named bubbles with one element
containing the data and name of the bubble chart. It is similar to previous charts however, the data should can
now contain size value to determine the size of a bubble. Example JSON:
https://www.apexofficeprint.com/docs/ 92/197
6/9/2019 APEX Office Print
{
"chart": {
"bubbles": [
{
"data": [
{
"x": "day 1",
"y": "4.3",
"size":"1"
},
{
"x": "day 2",
"y": "2.5",
"size":"3"
},
{
"x": "day 3",
"y": "3.5",
"size":"2"
}
],
"name": "Bubble series 1"
},
{
"data": [
{
"x": "day 1",
"y": "2.4",
"size":"4"
},
{
"x": "day 2",
"y": "4.4",
"size":"5"
},
{
"x": "day 3",
"y": "1.8",
"size":"1"
}
],
"name": "Bubble series 2"
}
],
"type": "bubble"
}
}
https://www.apexofficeprint.com/docs/ 93/197
6/9/2019 APEX Office Print
6.1.4.14 stock
This will produce a stock chart. The chart object should contain an array named stocks with one element
containing the data and name of the stock chart. Here instead of y value: volume, open, close, high and low
value should be given. The format of the x axis can also be given. The x axis contains the date starting using
1900 notation, i.e. 1 will represent January 1 1900 more info (https://support.office.com/en-us/article/Change-
the-date-system-format-or-two-digit-year-interpretation-aaa2159b-4ae8-4651-8bce-d4707bc9fb9f).
Example:
https://www.apexofficeprint.com/docs/ 94/197
6/9/2019 APEX Office Print
{
"chart": {
"stocks": [
{
"data": [
{
"x": "1",
"volume": "70",
"open": "44",
"high": "55",
"low": "11",
"close": "25"
},
{
"x": "2",
"volume": "120",
"open": "25",
"high": "57",
"low": "12",
"close": "38"
},
{
"x": "3",
"volume": "150",
"open": "38",
"high": "57",
"low": "13",
"close": "50"
},
{
"x": "4",
"volume": "135",
"open": "50",
"high": "58",
"low": "11",
"close": "35"
},
{
"x": "5",
"volume": "148",
"open": "34",
"high": "58",
"low": "25",
"close": "43"
}
],
"name": "s"
}
],
"type": "stock",
"options":{
"axis":{
"x":{
"date":{
"unit":"days",
"step":1,
https://www.apexofficeprint.com/docs/ 95/197
6/9/2019 APEX Office Print
"code":"dd"
}
}
}
}
},
"name": "Stocks"
}
https://www.apexofficeprint.com/docs/ 96/197
6/9/2019 APEX Office Print
"chart": {
"multiples": [
{
"columns": [
{
"data": [
{
"x": "day 1",
"y": "4.3"
},
{
"x": "day 2",
"y": "2.5"
},
{
"x": "day 3",
"y": "3.5"
}
],
"name": "bar 1"
},
{
"data": [
{
"x": "day 1",
"y": "2.4"
},
{
"x": "day 2",
"y": "4.4"
},
{
"x": "day 3",
"y": "1.8"
}
],
"name": "bar 2"
}
],
"type": "column"
},
{
"lines": [
{
"data": [
{
"x": "day 1",
"y2": "43"
},
{
"x": "day 2",
"y2": "25"
},
{
"x": "day 3",
"y2": "35"
https://www.apexofficeprint.com/docs/ 97/197
6/9/2019 APEX Office Print
}
],
"name": "line 1"
},
{
"data": [
{
"x": "day 1",
"y2": "24"
},
{
"x": "day 2",
"y2": "44"
},
{
"x": "day 3",
"y2": "18"
}
],
"name": "line 2"
}
],
"type": "line"
}
],
"options": {
"border": true,
"grid": true,
"height": 700,
"legend": {
"position": "r",
"showLegend": true
},
"title": false,
"width": 500
},
"type": "multiple"
}
https://www.apexofficeprint.com/docs/ 98/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 99/197
6/9/2019 APEX Office Print
select
'file1' as "filename",
cursor(select
cursor(select
c.cust_first_name || ' ' || c.cust_last_name as "customer",
c.cust_city as "city" ,
o.order_total as "total" ,
o.order_timestamp as "timestamp"
from demo_customers c, demo_orders o
where c.customer_id = o.customer_id
order by c.cust_first_name || ' ' || c.cust_last_name
) as "report",
cursor(select
'multiple' as "type",
'My Combo: Column with Line Chart' as "name",
cursor(select
576 as "width" ,
336 as "height",
'Title' as "title" ,
'true' as "grid",
'true' as "border",
cursor(select
'true' as "showLegend",
'r' as "position"
from dual
) as "legend"
from dual
) as "options",
cursor(select
tp as "type",
cursor(select
nm as "name",
cursor(select to_char(o.order_timestamp, 'MON RRRR') "label",
to_char(o.order_timestamp, 'MON RRRR') "x",
sum (decode(p.category,nm,oi.quantity * oi.unit_price,0)
from demo_product_info p, demo_order_items oi, demo_orders o
where oi.product_id = p.product_id
and o.order_id = oi.order_id
group by to_char(o.order_timestamp, 'MON RRRR'), to_char(o.ord
order by to_char(o.order_timestamp, 'RRRR MM')
) as "data"
from (select 'Mens' nm from dual union all select 'Womens' nm from dua
where tp = 'column'
) as "columns",
cursor(select
nm as "name",
cursor(select to_char(o.order_timestamp, 'MON RRRR') "label",
to_char(o.order_timestamp, 'MON RRRR') "x",
sum (decode(p.category,nm,oi.quantity * oi.unit_price,0)
from demo_product_info p, demo_order_items oi, demo_orders o
where oi.product_id = p.product_id
and o.order_id = oi.order_id
group by to_char(o.order_timestamp, 'MON RRRR'), to_char(o.ord
order by to_char(o.order_timestamp, 'RRRR MM')
) as "data"
from (select 'Accessories' nm from dual)
https://www.apexofficeprint.com/docs/ 100/197
6/9/2019 APEX Office Print
where tp = 'line'
) as "lines"
from (select 'column' tp from dual union all select 'line' tp from dua
) as "multiples"
from dual
) as "chart"
from dual
) as "data"
from dual
```
With Word/Excel/PowerPoint documents, it's possible to let AOP execute some JavaScript code to generate
```json
{
...
"files": [{
"filename": "output",
"data": {
"test": "CODE"
}
}]
}
https://www.apexofficeprint.com/docs/ 101/197
6/9/2019 APEX Office Print
// Based on https://bl.ocks.org/mbostock/7f5f22524bd1d824dd53c535eda0187f
const d3 = require('d3');
const D3Node = require('d3-node')
const d3n = new D3Node()
svg.append("g")
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).ticks(null, ".1f"))
.select(".tick:last-of-type text")
.select(function () { return this.parentNode.appendChild(this.cloneNode()); })
.attr("y", -3).attr("dy", null)
.attr("font-weight", "bold").text("Carats");
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y).ticks(null, ".1s"))
.select(".tick:last-of-type text")
.select(function () { return this.parentNode.appendChild(this.cloneNode()); })
.attr("x", 3).attr("text-anchor", "start")
.attr("font-weight", "bold").text("Price (USD)");
And a Word document containing {?d3 test} would produce the following result:
https://www.apexofficeprint.com/docs/ 102/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 103/197
6/9/2019 APEX Office Print
Should a field "test_data": [1,2,3] be present in the JSON (at the same place as "test": "CODE" ), then
the code will have access to the global data which would be [1,2,3] , or whatever "test_data" is. String,
booleans, nunbers and objects are also possible.
// Import D3
const d3 = require('d3');
// Import D3-Node
const D3Node = require('d3-node');
// Instantiate a new D3Node, which will provide the SVG and will be required to finish
const d3n = new D3Node();
// Create a SVG (instead of selecting one from the (here non-existing) document)
const svg = d3n.createSVG(512, 512); // Different sizes are possible
// Start working on the SVG
svg.append('g').text('Test');
// etc
// We can access the _data field if it was given:
svg.append('g').text(data ? data.toString() : 'No data passed!');
// When the SVG is finished, call the global finish() with the used D3Node object
finish(d3n);
// We can also call the global fail() (or throw an error) should something fail:
fail(new Error('We are missing something!'));
https://www.apexofficeprint.com/docs/ 104/197
6/9/2019 APEX Office Print
{
...
"files":[{
"filename" :"output",
"data":[{
"people":[{
"first_name" :"DemoName1",
"last_name" :"DemoLastName1",
"city" :"DemoCity1"},
{
"first_name" :"DemoName2",
"last_name" :"DemoLastName2",
"city" :"DemoCity2"},
{
"first_name" :"DemoName3",
"last_name" :"DemoLastName3",
"city" :"DemoCity3"}
]
}]
}]
}
The name of the employees are: {#people}{first_name}{last_name} from city {city}. {/people}
The name of the employees are: DemoName1 DemoLastName1 from City DemoCity1. DemoName2
DemoLastName2 from City DemoCity2. DemoName3 DemoLastName3 from City DemoCity3.
https://www.apexofficeprint.com/docs/ 105/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 106/197
6/9/2019 APEX Office Print
Results in:
https://www.apexofficeprint.com/docs/ 107/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 108/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 109/197
6/9/2019 APEX Office Print
Simple angular like expressions are also supported that can perform simple mathematical operations.
If the given key has a boolean value then you can use {#boolean key}…{/boolean key} to print the content
inside tags if the value of boolean key is true. For negation {^boolean key}…{/boolean key} is used. The
content inside these tags will be printed if the boolean key has false as value or if boolean key does not exists or
if boolean key is an empty array.
The numbers can also be compared in the same way as strings {#key>;50}…{/key>;50}.The content inside the
tags will be only printed if the value of the key is greater than 50. The following operators are supported: <, >,
<=, >=, ==, !=
https://www.apexofficeprint.com/docs/ 110/197
6/9/2019 APEX Office Print
{
...
"data":[{
"product":[{
"product_name" :"Business Shirt",
"quantity" :3,
"unit_price" :50,
"onstock" :true,
"cur" :"EUR"
},
{
"product_name" :"Trousers",
"quantity" :3,
"unit_price" :80,
"onstock" :false,
"cur" :"USD"
},
{
"product_name" :"Jacket",
"quantity" :3,
"unit_price" :15,
"onstock" :true,
"cur" :"USD"
},
{
"product_name" :"Blouse",
"quantity" :3,
"unit_price" :60,
"onstock" :false,
"cur" :"EUR"
}]
}]
}
https://www.apexofficeprint.com/docs/ 111/197
6/9/2019 APEX Office Print
Angular expressions can also be used inside floating texts. Below an example where the images are put inside
floating textbox and are shown under condition.
https://www.apexofficeprint.com/docs/ 112/197
6/9/2019 APEX Office Print
...
"data": {
"labels": [
{
"city": "city1",
"first_name": "firstname1",
"last_name": "lastname1",
"title": "Mr.",
"tracking_number_text": "TN49775377172",
"tracking_number": "TN49775377172",
"tracking_number_type": "code128",
"zip_code": 6981
},
...
{
"city": "city12",
"first_name": "firstname12",
"last_name": "lastname12",
"title": "Mr.",
"tracking_number_text": "TN49709864775",
"tracking_number": "TN49709864775",
"tracking_number_type": "code128",
"zip_code": 9740
}
]
}
...
and template:
https://www.apexofficeprint.com/docs/ 113/197
6/9/2019 APEX Office Print
will produce:
https://www.apexofficeprint.com/docs/ 114/197
6/9/2019 APEX Office Print
Note that in the first cell you need to add the {labels} tag. See also the Sample app.
https://www.apexofficeprint.com/docs/ 115/197
6/9/2019 APEX Office Print
<span style="..">..</span> : text between the span will have the style defined, background-color, color
"htmlcontent": "<p>This is text coming from the database / session in HTML format.
<br />It supports:
</p>
<ol>
<li>Lists</li>
<li><strong>Bold</strong></li>
<li><em>Italic</em></li>
<li><u>Underline</u></li>
<li><s>Strikethrough</s></li>
<li>Sub<sub>script</sub></li>
<li><sup>Super</sup>script</li>
<li><span style="color:#FF0000">Text Color</span></li>
<li><span style="background-color:#FFFF00">Background Text Color</span>
</li>
</ol>
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<p>Normalt text with<span style="font-family:comic sans ms,cursive"> Font Change</span></p>
<p><span style="font-family:courier new,courier,monospace">Code font</span>
</p>"
https://www.apexofficeprint.com/docs/ 116/197
6/9/2019 APEX Office Print
will produce:
https://www.apexofficeprint.com/docs/ 117/197
6/9/2019 APEX Office Print
Control Break: By clicking on Actions and selecting Control Break, one or more columns can be selected on
which the table should be broken. For the purpose of illustration, assume we select Quantity.
https://www.apexofficeprint.com/docs/ 118/197
6/9/2019 APEX Office Print
This splits the table up into partitions based on the value of the selected column. Thus, rows sharing the same
value for Quantity, will be grouped together into the same partition. The resulting table can be seen below:
As a final note, this option also supports the application of aggregates on the table data.
https://www.apexofficeprint.com/docs/ 119/197
6/9/2019 APEX Office Print
Group By: By clicking on Actions and selecting Group By, one or more columns can be selected on which the
table data should be grouped by. For the purpose of illustration, assume we select Quantity. Furthermore, one or
more functions can be applied on the table data. In this example, we request the sum of the unit price for every
group.
The result is a new table with one column for every selected column on which the data should be grouped by,
and one column for every selected function to be applied on the group data.
https://www.apexofficeprint.com/docs/ 120/197
6/9/2019 APEX Office Print
Additionally, a custom label and format may be selected for each function column and a sum can be performed
over the values of each function column.
Pivot: By clicking on Actions and selecting Pivot, the user is prompted to select at least one pivot column, at
least one row column and at least one function over a particular column. Important to note is that the row
column, pivot column and function column need to be different. For the sake of the example, we select Quantity
as a pivot column, Product Name as a row column and sum over Unit Price as a function.
https://www.apexofficeprint.com/docs/ 121/197
6/9/2019 APEX Office Print
The additional options supported in this case are the same as the ones in Group By.
Chart: AOP can also print your Interactive Report Chart view directly in your template by using {\$interactive}.
https://www.apexofficeprint.com/docs/ 122/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 123/197
6/9/2019 APEX Office Print
Note that this is a native PowerPoint chart, so you can adapt, make bigger, change colors, etc. directly in
PowerPoint.
Width Manipulation: Since 18.2.2 it is possible to manipulate the widths of the interactive columns. You can do
so by specifying it on HTML_EXPRESSION. You can use the following in html expression.
<span data-aop-width-weight="2"></span>#COLUMN_NAME#
The default weight for each column is 1. Let's say you have 4 columns and you provide this html expression in
the first colum. This will double the size of the first column in comparison to the remaining 3.
The following formula is used to calculate the percentage of width a column gets:
(weight of column)/(total weight provided for all the columns) * 100. Please note that these widths are the
desired widths. If the content does not fit, it could be that the minimum width that fits will be taken by
Word/LibreOffice.
https://www.apexofficeprint.com/docs/ 124/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 125/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 126/197
6/9/2019 APEX Office Print
{
"quote":"Only I can change my life. No one can do it for me.",
"person":"Carol Burnett"
}
https://www.apexofficeprint.com/docs/ 127/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 128/197
6/9/2019 APEX Office Print
{
"name": "Support",
"company_url": "https://www.apexofficeprint.com",
"company_url_text": "APEX RND",
"mail": "support@apexofficeprint.com"
}
https://www.apexofficeprint.com/docs/ 129/197
6/9/2019 APEX Office Print
The mail hyperlinks are automatically detected and mailto: will be appended for the link to work. The hyperlink
text can be given by giving extra data that ends with _text. e.g: {*tag_text}. (see json above).
Please note that in Excel the hyperlink will be added but the style will remain normal. You can change the tag
style in template if another styling is wished. In Word your default hyperlink styling will be taken. If you wish
another styling, you can change the style of the tag and add tag_preserve_tag_style:true options in the data.
https://www.apexofficeprint.com/docs/ 130/197
6/9/2019 APEX Office Print
{
...
"template": {
"filename": "Template",
"file": "UEsDBBAQBgQ...",
"template_type": "docx"
},
"templates": [
{
"name": "Subtemplate1",
"mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"file_source": "base64",
"file_content": "UEsDBBAQBgAIAA..."
}
]
}
with the template containing {?include Subtemplate1} would replace the tag with the contents of the
subtemplate.
This tag can be used inside loops, and tags inside the subtemplate will also be replaced.
For example:
{#products}
Product {name}
{?include Subtemplate1}
{/products}
Should the subtemplate just consist of the content Amount: {amount} , then this could be an example result:
Product Product1
Amount: 5
Product Product2
Amount: 36
This tag is currently only available inside Word templates, and the subtemplates currently can only be Word
documents (templates) too.
https://www.apexofficeprint.com/docs/ 131/197
6/9/2019 APEX Office Print
{
"template": {
"template_type": "pptx",
"filename": "demo.pptx"
},
"output": {
"output_encoding": "raw",
"output_type": "pptx"
},
"files": [
{
"filename": "output",
"data": [
{
"slide_title": "Slides Per Product",
"company_name": "Company A",
"product": [
{
"product_name": "Business Shirt",
"quantity": 3,
"unit_price": 50
},
{
"product_name": "Trousers",
"quantity": 3,
"unit_price": 80
},
{
"product_name": "Jacket",
"quantity": 3,
"unit_price": 15
},
{
"product_name": "Blouse",
"quantity": 3,
"unit_price": 60
}
]
}
]
}
]
}
https://www.apexofficeprint.com/docs/ 132/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 133/197
6/9/2019 APEX Office Print
Since there is only one item in root JSON object this is repeated only once. In template slide 2 we have specified
product array as our loop array with {!product} tag. Since there are 4 objects in our product array this template
will be repeated four times. The result is as follows:
https://www.apexofficeprint.com/docs/ 134/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 135/197
6/9/2019 APEX Office Print
Regular tags can be used with corresponding keyword in the JSON file between brackets, like in the docx and
pptx templates. The xlsx templates can loop over elements in a list by using the same technique as in the docx
template: {#loop_element} to enter the loop and {/loop_element} to close it. The cells that are in the rectangle
bounded by these two tags will be looped over and filled in using the data available in the JSON file. Nested
https://www.apexofficeprint.com/docs/ 136/197
6/9/2019 APEX Office Print
loops are possible (however keep in mind to remain within the rectangle formed by the "parent" loop – see note
after example below). Style will be copied from the template to the generated file accordingly. As with the docx
templates, simple angular expressions can be used to perform mathematical operations.
Xlsx example:
{
"template": {
"template_type": "xlsx",
"filename": "simple.xlsx"
},
"output": {
"output_encoding": "raw",
"output_type": "xlsx"
},
"files": [
{
"filename": "file1",
"data": [
{
"cust_first_name": "Albert",
"cust_last_name": "Lambert",
"cust_city": "St. Louis",
"orders": [
{
"order_total": 310,
"order_name": "Casual Shop's Order",
"product": [
{
"product_name": "Shirt",
"quantity": 3,
"unit_price": 50
},
{
"product_name": "Trousers",
"quantity": 2,
"unit_price": 80
}]
},
{
"order_total": 200,
"order_name": "Sport Shop's order",
"product": [
{
"product_name": "Sport's shoes",
"quantity": 2,
"unit_price": 100
}]
}]
}]
}]
}
https://www.apexofficeprint.com/docs/ 137/197
6/9/2019 APEX Office Print
Note: in the example above the {/orders} closing tag must be in the last column. Otherwise the child loops inside
{#orders}…{/orders}, in this case {#product}…{/product}, would not be able to generate inside the rectangle
formed between the tags of its parent loop ({#orders}…{/orders}).
Interactive Report in Excel: As of version 2.2, all of the functionalities supported in Word regarding the
interactive report are also supported in Excel. For the purpose of illustration, let's take this template as input:
https://www.apexofficeprint.com/docs/ 138/197
6/9/2019 APEX Office Print
6.3.1 {data_string_with_cell_markup$}
AOP 3.0 and above also supports cell settings. With a $ sign at the end of a tag, it is possible to specify different
styles in a cell. This allows user to change for example the background of the cell dynamically. An example of
such tag is {tag_with_style$}. The different styles then can be specified by appending either of the following in
the data: + cell_locked: [y/n] + cell_hidden: [y/n] + cell_background: hex color e.g: #ff0000 + font_name: name of
the font e.g: Arial + font_size: e.g 14, + font_color: hex color e.g: #00ff00 + font_italic: [y/n] + font_bold: [y/n] +
font_strike: [y/n] + font_underline: [y/n] + font_superscript:[y/n] + font_subscript:[y/n] + border_top: [dashed /
dashDot / hair / dashDotDot / dotted / mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot /
medium / double / thick ] + border_top_color: hex color e.g: #000000 + border_bottom: [dashed / dashDot / hair /
dashDotDot / dotted / mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot / medium /
double / thick ] + border_bottom_color: hex color e.g: #000000 + border_left: [dashed / dashDot / hair /
dashDotDot / dotted / mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot / medium /
double / thick ] + border_left_color: hex color e.g: #000000 + border_right: [dashed / dashDot / hair / dashDotDot
/ dotted / mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot / medium / double / thick ] +
border_right_color: hex color e.g: #000000 + border_diagonal: [dashed / dashDot / hair / dashDotDot / dotted /
mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot / medium / double / thick ] +
border_diagonal_direction: [up-wards|down-wards| both] + border_diagonal_color: hex color e.g: #000000 +
text_h_alignment: [top|bottom|center|justify] + text_v_alignment: [top|bottom|center|justify] + text_rotation:
rotation of text value from 0-90 degrees
Please note that if the tag is {example$} then the data provided should be inside example_cell_background,
example_font_italic ...e.t.c.
6.3.2 {!sheetgeneration}
https://www.apexofficeprint.com/docs/ 139/197
6/9/2019 APEX Office Print
With AOP 3.3 and above you can also generate sheets automatically by using {!tag} in any cell. This can be
used for example to generate a sheet report per customer. The sheet name can also be dynamically changed
and should be provided by the key "sheet_name". An example:
https://www.apexofficeprint.com/docs/ 140/197
6/9/2019 APEX Office Print
{
"customers": [
{
"sheet_name": "John Dulles", //sheet name!
"cust_first_name": "John",
"cust_last_name": "Dulles",
"cust_city": "Sterling",
"orders": [
{
"order_total": 2380,
"order_name": "Order 1",
"product": [
{
"product_name": "Business Shirt",
"quantity": 3,
"unit_price": 50
},
{
"product_name": "Trousers",
"quantity": 3,
"unit_price": 80
},
{
"product_name": "Jacket",
"quantity": 3,
"unit_price": 150
}
]
}
]
},
{
"sheet_name": "William Hartsfield",
"cust_first_name": "William",
"cust_last_name": "Hartsfield",
"cust_city": "Atlanta",
"orders": [
{
"order_total": 1640,
"order_name": "Order 1",
"product": [
{
"product_name": "Blouse",
"quantity": 4,
"unit_price": 60
},
{
"product_name": "Skirt",
"quantity": 4,
"unit_price": 80
}
]
},
{
"order_total": 730,
"order_name": "Order 2",
https://www.apexofficeprint.com/docs/ 141/197
6/9/2019 APEX Office Print
"product": [
{
"product_name": "Blouse",
"quantity": 4,
"unit_price": 60
}
]
}
]
}
]
}
https://www.apexofficeprint.com/docs/ 142/197
6/9/2019 APEX Office Print
6.3.4 {*hyperlink}
This is similar to hyperlink tag mentioned in section 6.1.16. In Excel, it is possible to hyperlink to a specific sheet
and cell inside the document itself. The URL then should be of structure: "SheetName!Cell". An example:
https://www.apexofficeprint.com/docs/ 143/197
6/9/2019 APEX Office Print
{
"examplehyperlink": "HyperlinkTarget!B2",
"examplehyperlink_text": "Go to HyperlinkTarget"
}
with template
https://www.apexofficeprint.com/docs/ 144/197
6/9/2019 APEX Office Print
Please note that the scope always starts at the default place, so the {#loop} tags have no effect.
https://www.apexofficeprint.com/docs/ 145/197
6/9/2019 APEX Office Print
6.5 Converter
This feature only works when the output_type is pdf
AOP can convert several types of files and/or append/prepend them to the outputted files.
https://www.apexofficeprint.com/docs/ 146/197
6/9/2019 APEX Office Print
{
...
"template": { ... },
"output": {
"output_encoding": "base64",
"output_type": "pdf" // Converter functionality only works with PDF as output_type
},
"files": [
{
"data": { ... },
"filename": "File1"
},
{
"data": { ... },
"filename": "File2"
},
...
],
"prepend_files": [
// Array of prepend files (see 6.5.1.2 File Structure)
{ ... },
{ ... },
...
],
"append_files": [
// Array of prepend files (see 6.5.1.2 File Structure)
{ ... },
{ ... },
...
]
}
{
"filename": "Filename",
"mine_type": "MIME TYPE",
// File source can be "plain", "base64", "url" or "file",
"file_source": "FILE SOURCE",
// Used by "file_source": "plain" and "base64",
"file_content": "...",
// Used by "file_source": "url",
"file_url": "http://...",
}
https://www.apexofficeprint.com/docs/ 147/197
6/9/2019 APEX Office Print
{
...
"files": [
{
"data": { ... },
"filename": "File1"
},
{
"data": { ... },
"filename": "File2"
},
...
],
}
Then, as might be expected, a zip archive will be returned containing File1.pdf and File2.pdf. The
append/prepend files will be appended/prepended to each file.
https://www.apexofficeprint.com/docs/ 148/197
6/9/2019 APEX Office Print
{
...
"template": {
// This template_type is template-less
"template_type": "converter"
},
"output": {
"output_encoding": "base64",
"output_type": "pdf", // Converter functionality only works with PDF as output_type
"icon_font": "Font Awesome 5" // Changes the rendering font used to generate icons when convert
},
// If the files array is empty, it'll default to a file with filename "Converted"
// Giving (multiple) files will just result in a zip archive with identical files, but with the giv
"files": [],
"prepend_files": [
// Array of prepend files (see 6.5.1.2 File Structure)
{ ... },
{ ... },
...
],
"append_files": [
// Array of prepend files (see 6.5.1.2 File Structure)
{ ... },
{ ... },
...
]
}
Should "files" be empty or only contain one file, and "append_files" or "prepend_files" only contain
one file, then the output file will just be that append/prepend file converted to PDF.
Mind that tags in append/prepend files will not be parsed! Append/prepend files are only converted and
appended/prepended to the output files.
https://www.apexofficeprint.com/docs/ 149/197
6/9/2019 APEX Office Print
7 SQL Structure
7.1 How to write SQL queries and map them to
template documents
Please refer to the image below containing SQL query and matching template.
AOP Plug-in supports PL/SQL cursor expressions which can be used in your templates as "data loops".
Left side corresponds to the SQL query that we used in our demo example. Right side is our Word template.
In SQL query you will notice three inner cursors called data, orders and product.
Idea is for each customer to find orders and products and display it as an invoice letter.
Data cursor is a standard part of AOP JSON structure and it needs to be present in all SQL queries. At the same
time you do not have to specify it as a loop in your template. For more details about this please reference
Section 9 of this Manual.
Other two cursor names can be of your preference as long as they are reflected in your template.
This is the way AOP engine merges your data with your templates.
In our template example you want to display customer details (Data cursor) and then display all their orders
(Orders cursor) with products (Product cursor) so each represents a separate cursor.
This means that we want to be able to create a loop for orders and a separate loop for products. This is exactly
what we have done in this template.
The way AOP template loop works is by using {#loop element}….{/loop element} notation. In the template notice
that we are using the following:
"Thank you for shopping at. We have following products reserved for you:
{#orders}{#product}
- {product_name}{/product}
The total amount of your order is €{order_total}.
{/orders}"
First open Orders loop then open Product loop then doing a bullet numbering for all products. Before closing the
Product loop and then closing the Orders loop.
Once you create your SQL query it is very easy to implement it in your template following few simple tagging
rules depending on a template type you are creating.
https://www.apexofficeprint.com/docs/ 150/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 151/197
6/9/2019 APEX Office Print
Unzip the downloaded file, you will see a directory with the version downloaded version number of AOP e.g
v18.1/
Go to the version directory/server directory and copy executable file on the server where you want AOP running
in a directory of your choice
Executable files:
OSX: APEXOfficePrintOSX64
Linux (Redhat): APEXOfficePrintLinux64
Windows: APEXOfficePrintWin64
Decide on which port you want to let AOP run. By default it is using port 8010. You can change that later (for
example APEXOfficePrintLinux64 -p 5555).
https://www.apexofficeprint.com/docs/ 152/197
6/9/2019 APEX Office Print
If you want to run the On-Premise Trial version of AOP you can skip the activation step.
The on-premise version of AOP in Trial mode will work with Word and PDF, but it contains a trial waterm
The cloud version of AOP (free 100 days) has no limitations.
Following step is only necessary when you bought AOP, it's not necessary to run in Trial mode (Linux
example):
run ./APEXOfficePrintLinux64 -a
this will activate the software
you have to enter the email you registered with and it will try to generate the license key. License key will
be generated if you have an open connection to the internet. If there’s no internet connection, or
something goes wrong with the activation, AOP will generate a license request file. You can upload this
license request file on your dashboard at https://www.apexofficeprint.com/. You can also contact
support@apexofficeprint.com and send this generated file as attachment. We’ll send you the license file
per email.
exit AOP
If that fails, make sure your environment variable PATH contains the directory of LibreOffice (bin directory). You
can also create a symbolic link to soffice e.g.
ln -s /opt/libreoffice5.4/program/soffice /usr/sbin/soffice
Note that if you choose to convert using libreoffice the conversion will be done in Parallel.
If you're on Windows, you can choose for LibreOffice or MS Office. In case you want to use MS Office, make
sure you have MS Office 2003 or higher installed and also install OfficetoPDF
(https://www.cognidox.com/officetopdf-converter/) (direct download
(https://github.com/cognidox/OfficeToPDF/releases)), which allows to run conversions from the command line.
Note: Place the OfficetoPDF executable location in the system PATH variable.
From version 18.1 onwards, it is possible to specify other converters. On the first run of APEXOfficePrint a
configuraion file, aop_config.json, is created. Below an example:
https://www.apexofficeprint.com/docs/ 153/197
6/9/2019 APEX Office Print
{
"config": {
"port": 8010,
"startat": "./",
"license": "./aop.license",
"silent": false,
"verbose": false,
"enable_printlog": false,
"idle_timeout": 120,
"instances": 1,
"https_key": "",
"https_cert": "",
"https_port": false,
"ipwhitelist": "",
"pdf_temp_folder": "",
"max_parallel_conversions":0,
"pdf_error_threshold": 3,
"enable_save": false,
"enable_local_resources": false,
"enable_macro": false
},
"converters": {
"abiword":{
"command": "abiword --to={outputFormat} --to-name={outputFile} {inputFile}",
"handlesParallel": false
}
},
"post_process_commands": {
"echo":"echo \"{inputFile} with input format ${inputFormat} has been successfully processed.\""
}
This allows for the users to use the converter of their choice. In the command section the following tags will be
replaced:
The other option handlesParallel should be true if the specified custom converter is capable of handling
multiple pdf conversions at the same time. If a custom converter is used and the specified converter cannot
handle parallel conversion, then the conversions are placed in a queue and called on first come first serve basis
(even when multiple instances of AOP are running).
Barcode option:
https://www.apexofficeprint.com/docs/ 154/197
6/9/2019 APEX Office Print
Before AOP 3.1 an external tool needed to be installed to be able to generate barcodes, but since AOP 3.1 and
above that is not necessary anymore. All the necessary components are within AOP itself.
Make sure the database server can connect to the port where AOP is running. If not, open the port so the
database server can connect to the webserver:port (note you don't need to open it up to everybody, just the
database server is fine)
For example by running curl webserver:port (curl can be downloaded for free for windows via
https://curl.haxx.se/download.html#Win64 (https://curl.haxx.se/download.html#Win64))
$ curl 127.0.0.1:8010
In the downloaded zip file there is also a sample application (app directory) that can be imported or you can just
import the AOP plug-in (plugin directory) into your application. The only configuration there is to define the
webserver:port where AOP is running and which converter you are using (LibreOffice, MS Office). You can do
that under Shared Components > Component Settings. Then select APEX Office Print (AOP) Plug-in, change
AOP URL and select appropriate converter.
8.2 Configuration
Following parameters can be used:
Only Word, PowerPoint and Excel templates can be created/processed in the TRIAL version of AOP. Once you
have decided on a license level, the product can be activated by running -a or --activate:
\$ APEXOfficePrintLinux64 -a
It will prompt for an email. Please use the same email you used when you subscribed for a license on
https://www.apexofficeprint.com/ (https://www.apexofficeprint.com/)
When running AOP again, it will show the new licensed templates you can use.
If there’s no internet connection, or something goes wrong with the activation, AOP will generate a license file
which you can upload on the dashboard at https://www.apexofficeprint.com/. Add the generated file in the same
directory of AOP and restart AOP to get the full version.
https://www.apexofficeprint.com/docs/ 155/197
6/9/2019 APEX Office Print
Since version 18.2 AOP creates a config file. These options can be saved in this config file. If no config file is
there, AOP generates the config file in the first run. This configuration file is of JSON format. The default
configuration is as follows:
https://www.apexofficeprint.com/docs/ 156/197
6/9/2019 APEX Office Print
{
"config": {
"port": 8010, // The port where AOP should start.
"startat": "./", // The default location to start at. Handly if you are using local resources.
"license": "./aop.license", // The location of the license file.
"silent": false, // If true does not log anything.
"verbose": false, // If true logs what it is currently doing. (Ignores silent)
"enable_printlog": false, // If true logs the incoming printjobs into a log file.
"idle_timeout": 120, // The timeout for conversion in seconds.
"instances": 1, // The number of instace to start. Ideally is equal to number of cores (if 0 AO
"https_key": "", // The location for the https key for AOP to use when starting in HTTPS mode.
"https_cert": "", // The locatio for the https certificate for AOP to use when startin in HTTPS
"https_port": 433, // The port to use while starting as HTTPS.
"ipwhitelist": "", // The location of the ipwhitelist file.
"pdf_temp_folder": "", // The temp folder to use when converting to PDF.
"max_parallel_conversions": 0 // The number of maximum parallel conversions allowed. 0 -> numbe
"pdf_error_threshold": 3, // The number of retries after pdf failure.
"enable_save": false, // Enables saving output in local directories.
"enable_local_resources": false // Enables reading out the templates and resources (for e.g ima
"enable_macro": false, // This allows docm and pptm templates to run macro's on event while pdf
},
"converters": { //Placeholder for converters. You can specify your own converters here and pass the
"abiword":{
"command": "abiword --to={outputFormat} --to-name={outputFile} {inputFile}",
"handlesParallel": false //From version 19.1 this can be a number, meaning x number of para
}
}
"post_process_commands":{ // Available since version 19.1, this allows you to execute custom comman
"echo":"echo \"{inputFile} with input format ${inputFormat} has been successfully processed.\""
}
}
32-Bit Windows
Directory Creation
Create a directory "Desktop" if it does not already exist under \
"C:\Windows\system32\config\systemprofile\Desktop"
DCOM config
2. Navigate to Component Services > Computers > My Computer > DCOM Config
https://www.apexofficeprint.com/docs/ 157/197
6/9/2019 APEX Office Print
4. Navigate to Security Tab and Customize the Launch and Activation Permissions and Edit
5. Check that no instances of excel.exe are running before changing the properties, either close the
applications that are running the Excel or go to task manager and kill the excel.exe processes.
https://www.apexofficeprint.com/docs/ 158/197
6/9/2019 APEX Office Print
6. Add the current user (type the current user, click check names, and click ok) and grant permission for
Local Launch and Local Activation
3. Under Security Tab add the current user and grant the Modify, Read & Execute, List Folder Content,
Read, and Write permissions.
64-Bit Windows
https://www.apexofficeprint.com/docs/ 159/197
6/9/2019 APEX Office Print
Directory Creation
"C:\Windows\system32\config\systemprofile\Desktop" and
"C:\Windows\SysWOW64\config\systemprofile\Desktop"
DCOM config
1. From Run (Windows + R), type dcomcnfg (if your Microsoft Office is 32 bit then open command line
and change directory to "C:\Windows\SysWOW64" and run "mmc comexp.msc /32" command)
2. Navigate to Component Services > Computers > My Computer > DCOM Config
4. Navigate to Security Tab and Customize the Launch and Activation Permissions and Edit
5. Check that no instances of excel.exe are running before changing the properties, either close the
applications that are running the Excel or go to task manager and kill the excel.exe processes.
https://www.apexofficeprint.com/docs/ 160/197
6/9/2019 APEX Office Print
6. Add the current user (type the current user, click check names, and click ok) and grant permission for
Local Launch and Local Activation
7. Go to Identity Tab and change the radio button to "The Interactive User" or "The Launching User"
(automatic start)
1. "C:\Windows\System32\config\systemprofile\AppData\Roaming\Microsoft".
3. Under Security Tab add the current user and grant the Modify, Read & Execute, List Folder Content,
Read, and Write permissions.
https://www.apexofficeprint.com/docs/ 161/197
6/9/2019 APEX Office Print
4. "C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft"
Note that you can also add additional parameters for example for the port it should run on and the starting
directory.
terminal
nssm.exe install APEXOfficePrint %0\..\..\APEXOfficePrintWin64.exe --port 8090 -s
D:\apexofficeprint
Run 1_SetupAsService.bat.
The service should be installed and can be seen in Services (Control Panel > Administrative Tools >
Services).
To change how the APEXOfficePrint services starts you can change it from Services or start it manually
via 2_StartService.bat (should be run as Administrator).
The APEXOfficePrint service should now be removed from Services. If it says Disabled then it will be
removed after the service has been stopped.
https://www.apexofficeprint.com/docs/ 162/197
6/9/2019 APEX Office Print
#!/bin/bash
#
# Apex Office Print (AOP) Server
#
# chkconfig: 345 70 30
# description: AOP is a print server for Oracle Application Express and PL/SQL
# processname: APEXOfficePrint
RETVAL=0
AOP_HOME=/opt/aop/v18.1/server
AOP_PROCESS_NAME=APEXOfficePrint
AOP_EXECUTABLE_NAME=APEXOfficePrintLinux64
AOP_PORT=8010
LIBREOFFICE_HOME=/opt/libreoffice5.4
PATH=$LIBREOFFICE_HOME/program:$PATH
export PATH
start() {
echo -n "Starting $AOP_PROCESS_NAME "
echo -n "Current path is $PATH"
$AOP_HOME/$AOP_EXECUTABLE_NAME -p $AOP_PORT -s $AOP_HOME &
RETVAL=$?
echo
return $RETVAL
}
stop() {
echo -n "Shutting down $AOP_PROCESS_NAME: "
pkill $AOP_PROCESS_NAME
RETVAL=$?
echo
return $RETVAL
}
status() {
echo -n "TODO: Print $AOP_PROCESS_NAME status here... "
RETVAL=$?
return $RETVAL
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
https://www.apexofficeprint.com/docs/ 163/197
6/9/2019 APEX Office Print
stop
start
;;
*)
echo "Usage: $prog {start|stop|status|restart}"
exit 1
;;
esac
exit $RETVAL
cd into /usr/lib/systemd/system
create a file aop.service
Paste the following in and adjust for your installation as required (personally I install AOP in /opt/oracle)
[Unit]
Description=APEX Office Print
After=network.target
[Service]
Type=simple
User=aop
Group=aop
Environment=PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/bin/
SyslogIdentifier=apexofficeprint
Restart=always
RestartSec=30
TimeoutStartSec=30
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
https://www.apexofficeprint.com/docs/ 164/197
6/9/2019 APEX Office Print
A simple setup is to install the version of aop in /opt/aop. When you install a new version just unzip in this
directory. You will end up for example with the following directories v3.4, v3.5 and v18.1. Create in the
directory /opt/aop a symbolic link to point to the latest version.
ln -s /opt/aop/v18.1 /opt/aop/latest
Suppose something is not working properly and you need to revert back to your previous version, all you need to
do is to create the symbolic link to a previous version. For example
unlink latest
ln -s /opt/aop/v3.3 /opt/aop/latest
As root
https://www.apexofficeprint.com/docs/ 165/197
6/9/2019 APEX Office Print
# extract tar
tar -xvf LibreOffice_5.4.7.2_Linux_x86-64_rpm.tar.gz
# install
cd /tmp/LibreOffice_5.4.7.2_Linux_x86-64_rpm/RPMS/
# install some missing dependencies (depending your linux version this is not necessary)
yum install cairo.x86_64
yum install cups.x86_64
yum install mesa-libGL.x86_64
openssl req -x509 -newkey rsa:2048 -keyout keytmp.pem -out aop.crt -days 365
openssl rsa -in keytmp.pem -out aop.key
Given aop.crt certificate file and aop.key private key file AOP can be started with:
The port number can also be specified with the --https_port argument. If this is provided HTTP and HTTPS
server will run.
You should see the following when started successfully on the console.
Please note that the certificate validation is done by the client. If you are using a self-signed certificate and visit
the https location with browser, you will get a security warning (see below).
https://www.apexofficeprint.com/docs/ 166/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 167/197
6/9/2019 APEX Office Print
You can configure the browsers to trust the self-signed certificate by adding it to the security exception. You will
also have to add this certificate in your oracle wallet to get rid of 'Certificate Validation Error'.
-------------------------------------------------
Error on Thu Feb 04 2016 19:33:35 GMT-0800 (PST)
-------------------------------------------------
listen EADDRINUSE
It means that the port you tried running AOP server is already taken and you need to change it by running this
command:
https://www.apexofficeprint.com/docs/ 168/197
6/9/2019 APEX Office Print
docker run -t -i \
--name ords \
--network=my_network \
-e DATABASE_HOSTNAME="oracle" \
-e DATABASE_PORT="1521" \
-e DATABASE_SERVICENAME="ORCLPDB1" \
-e DATABASE_PUBLIC_USER_PASS=oracle \
-e APEX_LISTENER_PASS=oracle \
-e APEX_REST_PASS=oracle \
-e ORDS_PASS=oracle \
--volume /docker/apex/images:/usr/local/tomcat/webapps/i \
-p 8181:8080
ords/ords_apex:3.0.9
Activating APEX Office Print the first time (Gold license only - not necessary for Enterprise license). This step is
only needed once.
In case you have an Enterprise License, add the aop.license file in the directory you specified, in the below
example it's /docker/apexofficeprint/
https://www.apexofficeprint.com/docs/ 169/197
6/9/2019 APEX Office Print
docker run -d \
--name apexofficeprint \
--network=my_network \
-p 8010:8010 \
-v /docker/apexofficeprint/:/apexofficeprintstartup/ \
apexrnd/apexofficeprint \
-s /apexofficeprintstartup/
You should now be able to connect to APEX Office Print server by going to http://apexofficeprint:8010/. You can
view this video (https://www.youtube.com/watch?v=U2RomOX_4_8) to see the above in action.
9 Tutorials
You can check the APEX Office Print tutorial page (https://www.apexofficeprint.com/ords/f?p=328:1) to see
tutorials and videos.
10 Troubleshooting
10.1 Output generates invalid Office documents
In case Office documents are not opening as expected, probably there was an issue with the JSON that was
send to the AOP server. If you run in the AOP Cloud, you can enable Remote Debugging, which you can access
when you login in your APEX Office Print dashboard at https://www.apexofficeprint.com
(https://www.apexofficeprint.com). If you're running the on-premise version of AOP, on the server there is a
server_error.log file that contains the errors it found during rendering. First step is to check that file for more
information. Next make sure that your JSON is valid by validating the JSON in for example http://jsonlint.com
(http://jsonlint.com) or by doing Remote Debug (see further on in this document)
https://www.apexofficeprint.com/docs/ 170/197
6/9/2019 APEX Office Print
You also might hit Oracle database bug (in 12.1.0.2). A patch is made available on https://support.oracle.com
(https://support.oracle.com); search for patch #21424376. You won't experience this issue in 11.2.0.4 or 12.2.
When using PL/SQL Function returning JSON, you might hit a bug in apex_plugin_util, which can be fixed by
applying patch 26048323.
Finally if you still encounter issues, use ORDS (SQL Workshop > RESTful Services) as your datasource. ORDS
will generate the JSON instead of apex_json and AOP will use that JSON instead (see 3.5.4 Data Source - URL
with ORDS RESTful Web Service).
Make sure APEX_050000 or APEX_050100 schema has the rights to connect to APEX Office Print
(http(s)://www.apexofficeprint.com for the Cloud version or your local URL in case of the on-premise version).
The script to correct the issue can be found here: APEX 5.0
(https://docs.oracle.com/cd/E59726_01/install.50/e39144/listener.htm#HTMIG29162) or for APEX 5.1
(http://docs.oracle.com/database/apex-5.1/HTMIG/enabling-network-services-in-Oracledb-11g-or-
later.htm#HTMIG29160) (use the correct script for your database version - for XE use prior to 12c)
https://www.apexofficeprint.com/docs/ 171/197
6/9/2019 APEX Office Print
In case you run over HTTPS you need to take into account the certificates. There're two ways to get around this:
Option 1: You can load our certificates in your Oracle wallet (the Oracle DB is doing the call to our server).
Option 2: You can add an entry in your webserver so a local entry is called by the database (which doesn't
need a certificate) and the webserver is doing the redirect to handle the https call.
Here's an example when in the plug-in you would specify a local address: http://apexrnd.localdomain/aop/
(http://apexrnd.localdomain/aop/)
<VirtualHost *:80>
ServerName apexrnd.localdomain
ServerAlias apexrnd.localdomain
RewriteEngine On
ProxyVia On
ProxyRequests Off
SSLProxyEngine On
ProxyPass /aop/ https://api.apexofficeprint.com/
ProxyPassReverse /aop/ https://api.apexofficeprint.com/
</VirtualHost>
Make a connection to your server with ssh or putty, but make sure you don't forward or tunnel your X Display.
Download LibreOffice
cd /tmp
wget http://download.documentfoundation.org/libreoffice/stable/5.4.2/rpm/x86_64/LibreOffice_5.4.2_Linux
Install LibreOffice
Add LibreOffice to the profile for your user (as it needs to be able to find soffice)
https://www.apexofficeprint.com/docs/ 172/197
6/9/2019 APEX Office Print
vi /etc/profile
export PATH=$PATH:/opt/libreoffice5.4/program
source /etc/profile
ln -s /opt/libreoffice5.4/program/soffice /usr/sbin/soffice
soffice --version
soffice --headless --invisible --convert-to pdf --outdir /tmp aop_interactive.docx
If you get: Fontconfig warning: ignoring UTF-8: not a valid region tag
echo "$LC_CTYPE"
|-> you probably have UTF-8 defined; unset it
export LC_CTYPE=""
Make sure you restart APEX Office Print after installing LibreOffice.
Note: we sometimes see LibreOffice doesn't generate the same PDF as MS Office is generating, but we found
LibreOffice becoming more and more inline, so we recommend using the latest version of LibreOffice.
Note: Depending the version of LibreOffice converting to HTML from docx, xlsx, pptx might include the images
as base64 or include a link.
https://www.apexofficeprint.com/docs/ 173/197
6/9/2019 APEX Office Print
If you are using APEX 5.1, the Dynamic Action plug-in will always work, whereas the Process plug-in might give
this error. When you put the process in the Processing part, it will only work if the “Reload on Submit” attribute
(of the page) is set to “Always” (note this attribute is new in 5.1). This is due to a change how APEX 5.1 is
handling Page Processing. If you would import an APEX 5.0 app in 5.1 by default it’s set to Always reload on
submit, but if you create a new app in 5.1 it’s set to “Only for Success” and then the process plug-in is not
working. Alternatively, you can put the AOP Process to be After Header and make it conditional, it will then work
regardless of the setting of "Reload on Submit".
If you receive "ORA-20000: Issue returned by AOP Service (REST call). Please verify the logs on the server.
Returned HTTP code: . (code: -29273)", see section 10.6.
Further more if you want to install additional fonts here's a good link (http://mscorefonts2.sourceforge.net). AOP
Cloud API has Google Noto (https://www.google.com/get/noto/) fonts installed.
Installing a font is nothing more than installing the font on your system. For example on (RedHat) Linux, we copy
the *.ttf files (or directory) to /usr/share/fonts/ and run "fc-cache -f -v"
Depending if you have a GUI (Linux/Windows) you can just double click on the font and it will install it in your
system. If your system recognises is, MS Office or LibreOffice should be able to use it for the PDF conversion.
For barcodes, you could also choose to install a barcode font, for example Free 3of9
(https://www.barcodesinc.com/free-barcode-font/) or http://www.dafont.com/3of9-barcode.font
(http://www.dafont.com/3of9-barcode.font). Barcode fonts are more performant than images.
If you are using font awesome and using html tag or interactive reports/grid in Word, you will have to install the
font-awesome desktop fonts in order to render on the PDFs properly. (AOP cloud server has free versions
installed.)
https://www.apexofficeprint.com/docs/ 174/197
6/9/2019 APEX Office Print
For older versions however we recommend setting up an Apache Reverse Proxy which is doing the SSL in front
of AOP. From Apache to AOP it would be unencrypted, but if it’s on the same machine as Apache and the port of
AOP is not open and only accessible by localhost, we believe you're save.
To prevent access to AOP other than the Apache Reverse Proxy, you can do (on Linux):
So that would mean only a program on localhost (like Apache) can connect to port 8010, all others are rejected.
make sure you're calling AOP also with HTTPS. If you're calling the AOP cloud https://api.apexofficeprint.com
(https://api.apexofficeprint.com) make sure to load the certificate in your database or setup a proxy on your end.
If you're using a proxy, make sure to specify the proxy in Shared Components > Application Definition Attributes
> Proxy Server or specify the global variable in the AOP_API_PKG.g_proxy_override.
See also further in this doc at chapter 14 Debugging connections to AOP Server
https://www.apexofficeprint.com/docs/ 175/197
6/9/2019 APEX Office Print
creation of JSON: your SQL statement or other source is taken to transform in JSON. You can trace what
is going on by setting your page in debug mode (APEX) or running your SQL statement in a SQL window.
time needed on the server by AOP: you can trace that by enabling logging (only on-premise) Start the
AOP server with --enable_printlog or --verbose, which will show the incoming requests.
network time: measure the time to travel from your database to our cloud or to your own on-premise
install. If you would use the on-premise version and put AOP on the same machine as the database, it
would be the fastest. Or if you could add it on another server where the network is fast, that should get rid
of the transfer time.
If the conclusion is that everything is as fast as possible, we advise the reports that take a long time, to run in the
background with a job. You could also schedule the reports to run overnight and store the results in a table.
https://www.apexofficeprint.com/docs/ 176/197
6/9/2019 APEX Office Print
The node stack of the XSL VM can be set with an event. It defaults to 300, the maximum is 4096. You can set it
with:
alter session set events='31153 trace name context forever, level 4096';
function addAOPXLSXDownloadToIR(pStaticIdItem) {
// hack into dialogopen event of jquery ui dialogs
$('body').on('dialogopen', function(event, ui) {
var dialogWindow$ = $(event.target);
// only process if it´s an IR download dialog
if (dialogWindow$.parents('div.ui-dialog').find('span.ui-dialog-title').text() === apex.lang.getMes
// get ID/static ID of IR
var currentRegionId = dialogWindow$.attr('id').match(/(.+)_dialog_js/)[1];
if (currentRegionId) {
// build html markup for XLSX download button
var html = apex.util.htmlBuilder();
html.markup('<li')
.attr('class', 'a-IRR-iconList-item')
.markup('>')
.markup('<a')
.attr('class', 'a-IRR-iconList-link')
.attr('href', 'javascript:$s("' + pStaticIdItem + '","' + currentRegionId + '")')
.attr('id', 'download_excel_aop')
.markup('>')
.markup('<span')
.attr('class', 'a-IRR-iconList-icon a-Icon icon-irr-dl-xls')
.markup('>')
.markup('</span>')
.markup('<span')
.attr('class', 'a-IRR-iconList-label')
.markup('>')
.markup('XLSX')
.markup('</span>')
.markup('</a>')
.markup('</li>');
// append html
$('.a-IRR-iconList').append(html.toString());
}
}
});
}
https://www.apexofficeprint.com/docs/ 177/197
6/9/2019 APEX Office Print
P0_AOP_IR_STATIC_ID
Create a page load DA (Execute JavaScript Code) on page 0 to call above JS function
addAOPXLSXDownloadToIR('P0_AOP_IR_STATIC_ID’);
Create a page 0 DA (On Change of “P0_AOP_IR_STATIC_ID”) which calls the AOP plugin
2 True Action (Execute JavaScript - To close the IR download dialog after download)
https://www.apexofficeprint.com/docs/ 178/197
6/9/2019 APEX Office Print
That´s it, the final result looks like this (on every IR in the app):
https://www.apexofficeprint.com/docs/ 179/197
6/9/2019 APEX Office Print
The data in the tables contains non-unicode characters. Most likely this is due to copy/paste of documents. It's
best to correct the data in the database, but if this can't be done, as a workaround in your query you can use
regexp_replace( COLUMN , '[[:cntrl:]]', '').
11 Debugging in APEX
AOP is fully instrumented with APEX debug messages, so when you turn debugging on in your APEX
application you will see many AOP: ... calls. Depending the level of APEX debug mode, more detailed debug
output will be available. See Dimitri Gielis's blog post (http://dgielis.blogspot.com/2018/06/error-whats-going-in-
apex-easiest-way.html) how to put APEX Trace on, which will show the most debug messages.
You can also specify a global variable g_debug_procedure if you want to call your own debug procedure which
for examples logs the information in your own table.
If you use Logger, you can also enable logger by compiling aop_api_pkg with a PL/SQL flag.
12 Debugging in PL/SQL
If you're scheduling reports or calling the AOP packages with PL/SQL you can debug straight from PL/SQL.
Here's an example:
https://www.apexofficeprint.com/docs/ 180/197
6/9/2019 APEX Office Print
declare
l_binds wwv_flow_plugin_util.t_bind_list;
l_return blob;
l_output_filename varchar2(100) := 'output';
begin
-- remove previous debug
apex_debug.remove_debug_by_age(
p_application_id => 232,
p_older_than_days => -1);
l_return := aop_api_pkg.plsql_call_to_aop (
p_data_type => aop_api_pkg.c_source_type_rpt,
p_data_source => 'ir1',
p_template_type => aop_api_pkg.c_source_type_apex,
p_template_source => 'aop_interactive.docx',
p_output_type => 'pdf',
p_output_filename => l_output_filename,
p_binds => l_binds,
p_aop_url => 'http://api.apexofficeprint.com/',
p_api_key => 'your API key',
p_app_id => 232,
p_page_id => 5,
p_init_code => 'aop_api_pkg.g_language := ''en'';');
end;
/
13 Remote Debugging
If you receive an error and you need some help of us, do following steps:
1) Go in your application to Shared Components > Component Settings > APEX Office Print (AOP) [Plug-in] and
enable remote debugging (see parameters screenshot)
![ ](media/aop_component_settings.png)
Note 1: you find your API key when you login in your dashboard on <https://www.apexofficeprint.com>
Note 2: Make sure APEX\_050000 or APEX\_050100 schema has the rights to connect to http(s)://www.apexof
![ ](media/aop_remote_debug.png)
https://www.apexofficeprint.com/docs/ 181/197
6/9/2019 APEX Office Print
4) Click on the magnifying glass, and the JSON that was generated behind the scenes which is send to the AOP
server component will be shown.
-) JSON is invalid: this is probably due to your version of APEX. If you are below APEX 5.1.2, you need a patch
linked to apex_json.
-) JSON is valid, but invalid Office file (Word, Excel, PowerPoint): this means that AOP couldn't merge your
data with the template you provided. If the template and requested output is the same format (e.g. your template
is in Word and you request a Word document); check your template again if all substitution strings are correct. If
you believe everything is ok, click the button "Sent to Support" and contact support@apexofficeprint.com
(mailto:support@apexofficeprint.com).
-) JSON is valid, but invalid PDF (or other output format): if the template and output format are different, a
conversion is going on handled by LibreOffice or MS Office. Either the conversion goes wrong, or most likely the
initial file before the conversion was already wrong. To debug further, set the output format to the same format
as your template and run your report again. If the output is invalid, follow previous steps (see JSON is valid, but
invalid Office file). If the output is ok, click the button "Sent to Support" and send an email to
support@apexofficeprint.com (mailto:support@apexofficeprint.com) as it means there's a bug in the conversion.
14 Local Debugging
If you receive an error and you need some help of us, do following steps:
1. Go in your application to Shared Components > Component Settings > APEX Office Print (AOP) [Plug-in]
and set Debug to Local.
2. Run your report again. A JSON file will now be downloaded instead of the report. This JSON is what is
sent to the AOP server component behind the scenes.
-) JSON is invalid: this is probably due to your version of APEX. If you are below APEX 5.1.2, you need a
patch linked to apex_json.
-) JSON is valid, but invalid Office file (Word, Excel, PowerPoint): this means that AOP couldn't
merge your data with the template you provided. If the template and requested output is the same format
(e.g. your template is in Word and you request a Word document); check your template again if all
substitution strings are correct. If you believe everything is ok, contact support@apexofficeprint.com
(mailto:support@apexofficeprint.com).
-) JSON is valid, but invalid PDF (or other output format): if the template and output format are
different, a conversion is going on handled by LibreOffice or MS Office. Either the conversion goes wrong,
or most likely the initial file before the conversion was already wrong. To debug further, set the output
format to the same format as your template and run your report again. If the output is invalid, follow
previous steps (see JSON is valid, but invalid Office file). If the output is ok, send an email to
support@apexofficeprint.com (mailto:support@apexofficeprint.com) as it means there's a bug in the
conversion.
https://www.apexofficeprint.com/docs/ 182/197
6/9/2019 APEX Office Print
4. If you didn't find a solution yourself, please send the JSON file to support@apexofficeprint.com
./APEXOfficePrintLinux64 —-verbose
Copy the test.json (./media/test.json) file to your server where AOP is running in /tmp folder
In another command prompt or shell go to /tmp folder and run (If you are in windows environment you can
download curl from https://curl.haxx.se/download.html#Win64 (https://curl.haxx.se/download.html#Win64)):
This should show the below output and have created an output.docx file
Prinjob received.
Sending back response.
Prinjob completed.
Try to run the same curl command but with your server name
curl -X POST -H 'Content-Type: application/json' -d @test.json http://<your server name>:8010/ > output
Go to the database server copy the test.json in the /tmp folder and run the curl command again
curl -X POST -H 'Content-Type: application/json' -d @test.json http://<your server name>:8010/ > output
Instead of using curl you can also use a RESTClient like Postman. You will have to add the header 'Content-
Type: application/json' and give the data from the test.json into the body section.
Go into APEX > SQL Workshop, and try to connect to the AOP server
https://www.apexofficeprint.com/docs/ 183/197
6/9/2019 APEX Office Print
Try to generate a first document, adjust the below script to your settings and run
declare
l_return blob;
l_output_filename varchar2(100) := 'output';
begin
aop_api_pkg.g_proxy_override := null; -- set the proxy if you use that
l_return := aop_api_pkg.plsql_call_to_aop (
p_data_type => 'SQL',
p_data_source => q'[
select
'file1' as "filename",
cursor(
select 'hello world' as "string"
from dual
) as "data"
from dual
]',
p_template_type => null,
p_template_source => null,
p_output_type => 'docx',
p_output_filename => l_output_filename,
p_aop_url => 'http://<your server name>:8010/', -- change to the AOP server
p_api_key => '',
p_app_id => 232); -- change to the AOP sample app number
sys.htp.p(dbms_lob.getlength(l_return));
end;
In the shell where AOP is running you should see the incoming connection.
Hopefully the below steps give you more insight where your connection is failing so you can correct accordingly.
16 FAQ
-) Does AOP have to go on its own server, the database server or the application (ORDS) server?
You can choose. Having AOP on the same server as the database machine is most performant and easiest as
you don’t have network connections to other servers. If you install AOP on its own server you can size and
monitor that server better. AOP on the Application server is another option, as long as the database can connect
to the AOP server component, the AOP server doesn't need to be accessible from the outside (clients). So it’s
whatever you are most comfortable with.
-) Is there anything special we have to do with AOP to get it to work with SSL?
You can add a reverse proxy for the SSL or you can specify the https certificate when starting the AOP server
itself. Most people don’t do SSL as it’s only the database that needs to access the AOP server component, so
typically you don’t even pass the network where others are. However AOP can start in SSL mode if the SSL
certificate and its key are provided via --https_key and --https_cert argument.
https://www.apexofficeprint.com/docs/ 184/197
6/9/2019 APEX Office Print
If you are using HTTPS (we always recommend you to do this) for connecting with the API server, you might get
a SSL certification validation error:
ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1130 ORA-29024: Certificate
validation failure In this case you will have to load the SSL certificate of the root certification authority, in our
case that of GoDaddy, into your oracle wallet. You can get this certificate by visiting https://apexofficeprint.com/
and looking at the certificate information. Example firefox:
-) How resource intensive is it? Does it eat up a lot of CPU, RAM, or hard drive space?
It depends how many prints you do… AOP initially consumes about 400MB RAM, but depending the prints it can
go up to 4GB (a limit we put). In case you have larger documents, we recommend downloading the high
memory version which can consume up to 16GB. CPU is not much compared to the specs these days and hard
drive space is about 500MB. The executable is about 500MB and we might create some temporary files (during
pdf conversion) and a log and error file.
https://www.apexofficeprint.com/docs/ 185/197
6/9/2019 APEX Office Print
-) Do I have to install LibreOffice when we need Word and Excel output only?
No - LibreOffice or MS Office is only used when you want to convert from one format to another. So Word-Word
or Excel-Excel is working without. But if you want to do for example Word->PDF you need LibreOffice or MS
Office or another converter you prefer.
AOP 3.1 and above includes the ability to print directly to an IP Printer, as long as it's available from the server
AOP is running on. If you want to print to a local printer, check the Sample app how to print to an inline region,
by adding a little bit of JavaScript to the dynamic action you can let the browser come up with a print window
automatically.
Yes, this is a setting in Office. When you right click on your header row in Word, you can go to Table Properties -
Row and check the "Repeat as header row at the top of every page". An example is given on page 113 of
sample application.
Yes, you can use the transpose function in Excel to pivot your data. AOP can also loop vertically by using the
{:tag}.
When going from Word to PDF, we use an external converter: MS Office or LibreOffice. It might be that if your
template was built on your desktop in MS Office (Word), but your server is using LibreOffice (Linux) a font is
different or there are minimal changes. The easiest way to find out what the difference is, is to open the template
in LibreOffice on your Desktop and see why LibreOffice is treating it different. In most use cases it works just fine
going from one to the other, but sometimes it's in the details.
-) Can I install the APEX Plug-in somewhere so all my apps have access to it?
You can make the aop_api_pkg a public synonym for aop_api19_pkg PL/SQL package in case you only want
the package in a global schema. The Oracle APEX plug-in itself you would still need to import in every APEX
application you want to use it in, but the plug-in can point to the public package.
Yes. In some cases, you might want to start a new page for every record for example for certificates. You can put
the page break inside a conditional expression. You can use the rownum function to generate the id for every
record and check if that is equals to the record length. An example is shown in page 119 of our sample
application. Given the data:
https://www.apexofficeprint.com/docs/ 186/197
6/9/2019 APEX Office Print
select
'file1' as "filename",
cursor(
select
cursor(
select
rownum as "customerIndex",
c.cust_first_name as "cust_first_name",
c.cust_last_name as "cust_last_name"
from demo_customers c
) as "customers"
from dual
) as "data"
from dual
You can use the following tag to insert page break for every record except for the last.
{#customerIndex!=customers.length}
-------------page break ------------
{/customerIndex!=customers.length}
Please note that if you wish to output to pdf, the same can be achieved by using the PowerPoint template and
{!slides_loop} tag. In this case there is no need to use the rownum function.
-) Can I adjust the width and height of interactive report/grid export in Word?
If you are exporting interactive grid, you can adjust the columns width as you like (due to meta data issue you
will also have to change the width a bit for all columns.). The ratio is then automatically taken into account.
<span data-aop-width-weight="2"></span>#COLUMN_NAME#
The default weight for each column is 1. Let's say you have 4 columns and you provide this html expression in
the first column. This will double the size of the first column in comparison to the remaining 3.
The following formula is used to calculate the percentage of width a column gets:
Since version 19.1.4 AOP allows to specify the width in either px,in,cm,em or pt. Use the following HTML
EXPRESSION:
<span data-aop-width="10px"></span>#COLUMN_NAME#
If AOP detects this in one of the columns, the columns which do not have this expression will get the minimum
width specified.
-) How can I show custom success and error messages using AOP Dyncamic Action Plugin?
https://www.apexofficeprint.com/docs/ 187/197
6/9/2019 APEX Office Print
You can defines another TRUE action before the AOP Plugin is triggered and overwrite the
showSuccessMessage and showErrorMessage functions.
17 Example Templates
Below we illustrate some example templates and the generated output.
Example 1
This is the input template:
https://www.apexofficeprint.com/docs/ 188/197
6/9/2019 APEX Office Print
This is the result after AOP has processed the template and the given data:
https://www.apexofficeprint.com/docs/ 189/197
6/9/2019 APEX Office Print
Example 2
This is the input template:
https://www.apexofficeprint.com/docs/ 190/197
6/9/2019 APEX Office Print
This is the result after AOP has processed the template and the given data:
https://www.apexofficeprint.com/docs/ 191/197
6/9/2019 APEX Office Print
Example 3
This is the input template:
https://www.apexofficeprint.com/docs/ 192/197
6/9/2019 APEX Office Print
This is the result after AOP has processed the template and the given data:
https://www.apexofficeprint.com/docs/ 193/197
6/9/2019 APEX Office Print
Example 4
This is the input template:
https://www.apexofficeprint.com/docs/ 194/197
6/9/2019 APEX Office Print
This is the result after AOP has processed the template and the given data:
https://www.apexofficeprint.com/docs/ 195/197
6/9/2019 APEX Office Print
Copyright
Copyright © 2015-2019, APEX R&D (https://www.apexrnd.be)
This software and related documentation are provided under a license agreement containing restrictions on use
and disclosure that are protected by intellectual property laws. Except as expressly permitted in your license
agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit,
distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse engineering,
disassembly, or de-compilation of this software, unless required by law for interoperability, is prohibited. The
information contained herein is subject to change without notice and is not warranted to be error-free. If you find
any errors, please report them to us in writing.
https://www.apexofficeprint.com/docs/ 196/197
6/9/2019 APEX Office Print
https://www.apexofficeprint.com/docs/ 197/197