Using PDF as a template
AOP empowers you to use existing PDF documents as templates, dynamically populating them with data from your application. This feature is ideal for generating standardized business documents such as invoices, reports, or certificates where a consistent layout must be maintained while the content varies.
Key Features
- Text Insertion: Seamlessly inject dynamic text into predefined locations within your PDF template.
- Image Insertion: Embed images (logos, signatures, QR codes) dynamically into designated areas.
- Page Repeating: Automatically duplicate pages for iterating over datasets, perfect for multi-item invoices or batch processing.
Understanding PDF Tags
To make a PDF template interactive, you place special placeholders called "tags" in the document. AOP recognizes three primary tag types:
| Tag Type | Syntax | Purpose | Example |
|---|---|---|---|
| Text | {tagname} | Replaced with text values from your data | {customer_name} |
| Image | {%tagname} | Replaced with images (URL or Base64) | {%company_logo} |
| Repeat | {!tagname} | Duplicates the page for each item in an array | {!invoice_items} |
Download a sample tagged template:
Let's explore each tag type with practical examples.
Text Insertion
Text tags are the most common way to inject dynamic data into your PDF. Simply place {tagname} in your PDF template where you want the text to appear, and AOP will replace it with the corresponding value from your data source.
Example Scenario: Generate an invoice header with customer details.
Data Source
- SQL
- PL/SQL returning SQL
- PL/SQL returning JSON
- JSON
SELECT
'file1' AS "filename",
CURSOR (
SELECT
'John Doe' as "customer_name",
'INV-2025-001' as "invoice_number",
TO_CHAR(SYSDATE, 'YYYY-MM-DD') as "issue_date",
'$1,500.00' as "amount"
FROM
dual
) AS "data"
FROM
dual;
declare
l_return clob;
begin
l_return := q'[
SELECT
'file1' AS "filename",
CURSOR (
SELECT
'John Doe' as "customer_name",
'INV-2025-001' as "invoice_number",
TO_CHAR(SYSDATE, 'YYYY-MM-DD') as "issue_date",
'$1,500.00' as "amount"
FROM
dual
) AS "data"
FROM
dual;
]';
return l_return;
end;
declare
l_cursor sys_refcursor;
l_return clob; -- can also be varchar2, make sure it corresponds to the structure in the JSON
begin
apex_json.initialize_clob_output(dbms_lob.call, true, 2);
open l_cursor for
SELECT
'file1' AS "filename",
CURSOR (
SELECT
'John Doe' as "customer_name",
'INV-2025-001' as "invoice_number",
TO_CHAR(SYSDATE, 'YYYY-MM-DD') as "issue_date",
'$1,500.00' as "amount"
FROM
dual
) AS "data"
FROM
dual;
apex_json.write(l_cursor);
l_return := apex_json.get_clob_output;
return l_return;
end;
{
"filename": "file1",
"data" : [{
"customer_name": "John Doe",
"invoice_number": "INV-2025-001",
"issue_date": "2024-06-15",
"amount": "$1,500.00"
}]
}
How to use in your PDF template:
Place these tags in your PDF document:
{customer_name}→ Replaced with "John Doe"{invoice_number}→ Replaced with "INV-2025-001"{issue_date}→ Replaced with the current date{amount}→ Replaced with "$1,500.00"
Template
Output
Image Insertion
Image tags enable you to dynamically place visuals in your PDF. Use the {%tagname} syntax to insert images from URLs or Base64-encoded strings.
Example Scenario: Add a company logo, digital signature, and QR code to an invoice.
- SQL
- PL/SQL returning SQL
- PL/SQL returning JSON
- JSON
SELECT
'file1' AS "filename",
CURSOR (
SELECT
'https://example.com/logo.png' as "company_logo",
l_base64_signature_image as "signature",
'https://example.com/qr/INV-2025-001.png' as "qr_code"
FROM
dual
) AS "data"
FROM
dual;
declare
l_return clob;
begin
l_return := q'[
SELECT
'file1' AS "filename",
CURSOR (
SELECT
'https://example.com/logo.png' as "company_logo",
l_base64_signature_image as "signature",
'https://example.com/qr/INV-2025-001.png' as "qr_code"
FROM
dual
) AS "data"
FROM
dual;
]';
return l_return;
end;
declare
l_cursor sys_refcursor;
l_return clob; -- can also be varchar2, make sure it corresponds to the structure in the JSON
begin
apex_json.initialize_clob_output(dbms_lob.call, true, 2);
open l_cursor for
SELECT
'file1' AS "filename",
CURSOR (
SELECT
'https://example.com/logo.png' as "company_logo",
l_base64_signature_image as "signature",
'https://example.com/qr/INV-2025-001.png' as "qr_code"
FROM
dual
) AS "data"
FROM
dual;
apex_json.write(l_cursor);
l_return := apex_json.get_clob_output;
return l_return;
end;
{
"data": [
{
"company_logo": "https://example.com/logo.png",
"signature": "iVBORw0KGgoAAAANSUhEUgAA...",
"qr_code": "https://example.com/qr/INV-2025-001.png"
}
]
}
How to use in your PDF template:
Place these image tags in your PDF document:
{%company_logo}→ Inserts the company logo{%signature}→ Inserts the signature image{%qr_code}→ Inserts the QR code
Template
Output
Page Repeating
The Page Repeat tag, {!tagname}, is a powerful feature for batch processing and multi-item documents.
How it works:
- Place
{!tagname}anywhere on a PDF page - AOP looks for an array of objects in your data under
tagname - For each item in that array, AOP duplicates the entire page and populates it with that item's data
Example Scenario: Generate an employee profile card for every employee in your system.
Data Source
- SQL
- PL/SQL returning SQL
- PL/SQL returning JSON
- JSON
SELECT
'file1' AS "filename",
CURSOR (
SELECT
json_arrayagg(
json_object(
'name' value e.name,
'role' value e.role,
'department' value e.department,
'city' value e.city,
'country' value e.country,
'salary' value e.salary,
'active' value e.active,
'companyLogo' value e.logo_base64,
'companyLogo_width' value 150,
'companyLogo_height' value 80
)
) AS "items"
FROM employees e
) AS "data"
FROM
dual;
declare
l_return clob;
begin
l_return := q'[
SELECT
'file1' AS "filename",
CURSOR (
SELECT
json_arrayagg(
json_object(
'name' value e.name,
'role' value e.role,
'department' value e.department,
'city' value e.city,
'country' value e.country,
'salary' value e.salary,
'active' value e.active,
'companyLogo' value e.logo_base64,
'companyLogo_width' value 150,
'companyLogo_height' value 80
)
) AS "items"
FROM employees e
) AS "data"
FROM
dual;
]';
return l_return;
end;
declare
l_cursor sys_refcursor;
l_return clob; -- can also be varchar2, make sure it corresponds to the structure in the JSON
begin
apex_json.initialize_clob_output(dbms_lob.call, true, 2);
open l_cursor for
SELECT
'file1' AS "filename",
CURSOR (
SELECT
json_arrayagg(
json_object(
'name' value e.name,
'role' value e.role,
'department' value e.department,
'city' value e.city,
'country' value e.country,
'salary' value e.salary,
'active' value e.active,
'companyLogo' value e.logo_base64,
'companyLogo_width' value 150,
'companyLogo_height' value 80
)
) AS "items"
FROM employees e
) AS "data"
FROM
dual;
apex_json.write(l_cursor);
l_return := apex_json.get_clob_output;
return l_return;
end;
{
"items": [
{
"name": "Kiran Kandel",
"role": "Software Engineer",
"department": "AOP",
"city": "Kathmandu",
"country": "Nepal",
"salary": 95000,
"active": true,
"companyLogo": "iVBORw0KGgoAAAANSUhEUgAAAi8AAAGMCAMAAAAlarKrAAADAFBMVEUAAAD...",
"companyLogo_width": 150,
"companyLogo_height": 80
},
{
"name": "Rabin Ghimire",
"role": "Software Engineer",
"department": "Engineering",
"city": "New York",
"country": "USA",
"salary": 120000,
"active": true,
"companyLogo": "iVBORw0KGgoAAAANSUhEUgAAAi8AAAGMCAMAAAAlarKrAAADAFBMVEUAAAD...",
"companyLogo_width": 150,
"companyLogo_height": 80
},
{
"name": "Anush Mali",
"role": "Product Designer",
"department": "AOE",
"city": "Kirtipur",
"country": "Nepal",
"salary": 185000,
"active": false,
"companyLogo": "iVBORw0KGgoAAAANSUhEUgAAAi8AAAGMCAMAAAAlarKrAAADAFBMVEUAAAD...",
"companyLogo_width": 150,
"companyLogo_height": 80
}
]
}