xlsx-png
XLSX Writer is a PL/SQL library that allows to create Excels in the .xlsx document format.
Please use my blog post for questions, comments etc.

Examples

1. Adding a sheet

The first example demonstrates the basic structure of a PL/SQL program that uses the XLSX library. The created Excel document is accordingly simple:
ex01
declare

  workbook xlsx_writer.book_r;
  sheet    integer;

  xlsx     blob;

begin

  workbook := xlsx_writer.start_book;
  sheet    := xlsx_writer.add_sheet  (workbook, 'Name of the sheet');
  xlsx     := xlsx_writer.create_xlsx(workbook);

  blob_wrapper.to_file('XLSX_WRITER_TEST_DIR', '01_add_sheet.xlsx', xlsx);

end;
/
Source on Github

2. Filling some cells

The second example writes some data into the cells. I am almost a bit proud on how easy this is.
ex02
declare

  workbook xlsx_writer.book_r;
  sheet    integer;

  xlsx     blob;

begin

  workbook := xlsx_writer.start_book;
  sheet    := xlsx_writer.add_sheet  (workbook, 'Name of the sheet');

  xlsx_writer.add_cell(workbook, sheet, 1, 1, text => 'foo'); 
  xlsx_writer.add_cell(workbook, sheet, 2, 2, text => 'bar'); 
  xlsx_writer.add_cell(workbook, sheet, 3, 3, text => 'baz'); 
  xlsx_writer.add_cell(workbook, sheet, 4, 4, text => '<&>'); -- Will it be replaced with correct entities?

  xlsx_writer.add_cell(workbook, sheet, 1, 4, value_ => 42   ); 
  xlsx_writer.add_cell(workbook, sheet, 2, 4, date_  => date '2015-08-28' + 13/17);  -- Note, should also use a specific date format
  xlsx_writer.add_cell(workbook, sheet, 3, 4, value_ => 21.21); 

  xlsx     := xlsx_writer.create_xlsx(workbook);

  blob_wrapper.to_file('XLSX_WRITER_TEST_DIR', '02_fill_cells.xlsx', xlsx);

end;
/
Source on Github

3. Working with cell styles

Cell styles allow to format the content of a cell, for example some text should be displayes with the courier font, some other text bold or italic, some figures with two decimal places and a percent sign:
ex03
declare

  workbook xlsx_writer.book_r;
  sheet                   integer;

  xlsx                    blob;

  font_courier            integer;
  cs_courier              integer;

  font_bold               integer;
  cs_bold                 integer;

  font_italic             integer;
  cs_italic               integer;

  font_underl             integer;
  cs_underl               integer;

 "mm-dd-yy"               integer;
 "0"                      integer;
 "0.00"                   integer;
 "#.##0"                  integer;
 "#.##0.00"               integer;
 "0%"                     integer;
 "0.00%"                  integer;
 "h:mm:ss"                integer;

  cs_top_wrapped          integer;
  cs_center_wrapped       integer;
  cs_bottom_wrapped       integer;

begin

  workbook     := xlsx_writer.start_book;
  sheet        := xlsx_writer.add_sheet     (workbook, 'Name of the sheet');
  font_courier := xlsx_writer.add_font      (workbook, 'Courier New', 12);
  font_bold    := xlsx_writer.add_font      (workbook, 'Arial'      , 12, b => true);
  font_italic  := xlsx_writer.add_font      (workbook, 'Georgia'    , 12, i => true);
  font_underl  := xlsx_writer.add_font      (workbook, 'Verdana'    , 12, u => true);

  xlsx_writer.col_width(workbook, sheet, 1   , 45); -- col_width, variant one
  xlsx_writer.col_width(workbook, sheet, 2, 2, 14); -- col_widht, variant two

  cs_courier   := xlsx_writer.add_cell_style(workbook, font_id => font_courier);
  cs_bold      := xlsx_writer.add_cell_style(workbook, font_id => font_bold);
  cs_italic    := xlsx_writer.add_cell_style(workbook, font_id => font_italic);
  cs_underl    := xlsx_writer.add_cell_style(workbook, font_id => font_underl);


 "mm-dd-yy"          := xlsx_writer.add_cell_style(workbook, num_fmt_id => xlsx_writer."mm-dd-yy");
 "0"                 := xlsx_writer.add_cell_style(workbook, num_fmt_id => xlsx_writer."0"       );
 "0.00"              := xlsx_writer.add_cell_style(workbook, num_fmt_id => xlsx_writer."0.00"    );
 "#.##0"             := xlsx_writer.add_cell_style(workbook, num_fmt_id => xlsx_writer."#.##0"   );
 "#.##0.00"          := xlsx_writer.add_cell_style(workbook, num_fmt_id => xlsx_writer."#.##0.00");
 "0%"                := xlsx_writer.add_cell_style(workbook, num_fmt_id => xlsx_writer."0%"      );
 "0.00%"             := xlsx_writer.add_cell_style(workbook, num_fmt_id => xlsx_writer."0.00%"   );
 "h:mm:ss"           := xlsx_writer.add_cell_style(workbook, num_fmt_id => xlsx_writer."h:mm:ss" );

  cs_top_wrapped     := xlsx_writer.add_cell_style(workbook, vertical_alignment => 'top'   , wrap_text => true);
  cs_center_wrapped  := xlsx_writer.add_cell_style(workbook, vertical_alignment => 'center', wrap_text => true);
  cs_bottom_wrapped  := xlsx_writer.add_cell_style(workbook, vertical_alignment => 'bottom', wrap_text => true);

  xlsx_writer.add_cell(workbook, sheet,  1, 1, style_id => cs_courier, text => 'Courier'   ); 
  xlsx_writer.add_cell(workbook, sheet,  2, 1, style_id => cs_bold   , text => 'Bold'      ); 
  xlsx_writer.add_cell(workbook, sheet,  3, 1, style_id => cs_italic , text => 'Italic'    ); 
  xlsx_writer.add_cell(workbook, sheet,  4, 1, style_id => cs_underl , text => 'Underlined'); 

  xlsx_writer.add_cell(workbook, sheet,  5, 1, text => 'Date in mm-dd-yy'); 
  xlsx_writer.add_cell(workbook, sheet,  5, 2, style_id => "mm-dd-yy", date_ => date '2015-06-05'); 

  xlsx_writer.add_cell(workbook, sheet,  6, 1, text => 'Number 12345.678 in "0"'); 
  xlsx_writer.add_cell(workbook, sheet,  6, 2, style_id => "0", value_ => 12345.678); 

  xlsx_writer.add_cell(workbook, sheet,  7, 1, text => 'Number 12345.678 in "0.00"'); 
  xlsx_writer.add_cell(workbook, sheet,  7, 2, style_id => "0.00", value_ => 12345.678); 

  xlsx_writer.add_cell(workbook, sheet,  8, 1, text => 'Number 12345.678 in "#.##0"'); 
  xlsx_writer.add_cell(workbook, sheet,  8, 2, style_id => "#.##0", value_ => 12345.678); 

  xlsx_writer.add_cell(workbook, sheet,  9, 1, text => 'Number 12345.678 in "#.##0.00"'); 
  xlsx_writer.add_cell(workbook, sheet,  9, 2, style_id => "#.##0.00", value_ => 12345.678); 

  xlsx_writer.add_cell(workbook, sheet, 10, 1, text => 'Number 0.1783 in "0%"'); 
  xlsx_writer.add_cell(workbook, sheet, 10, 2, style_id => "0%", value_ => 0.1783); 

  xlsx_writer.add_cell(workbook, sheet, 11, 1, text => 'Number 0.1783 in "0.00%"'); 
  xlsx_writer.add_cell(workbook, sheet, 11, 2, style_id => "0.00%", value_ => 0.1783); 

  xlsx_writer.add_cell(workbook, sheet, 12, 1, text => 'Number 21/24+13/24/60+48/24/60/60 in "h:mm:ss"'); 
  xlsx_writer.add_cell(workbook, sheet, 12, 2, style_id => "h:mm:ss", value_ => 21/24+13/24/60+48/24/60/60); 

  xlsx_writer.add_row(workbook , sheet, 13, 80);
  xlsx_writer.add_cell(workbook, sheet, 13, 1, style_id => cs_top_wrapped, text => 'This is quite a long text that is supposed to demonstrate the effect of using vertical_alignment=>''top'' and text_wrap=>true'); 

  xlsx_writer.add_row(workbook , sheet, 14, 80);
  xlsx_writer.add_cell(workbook, sheet, 14, 1, style_id => cs_center_wrapped, text => 'This is quite a long text that is supposed to demonstrate the effect of using vertical_alignment=>''center'' and text_wrap=>true'); 

  xlsx_writer.add_row(workbook , sheet, 15, 80);
  xlsx_writer.add_cell(workbook, sheet, 15, 1, style_id => cs_bottom_wrapped, text => 'This is quite a long text that is supposed to demonstrate the effect of using vertical_alignment=>''bottom'' and text_wrap=>true'); 

  xlsx     := xlsx_writer.create_xlsx(workbook);

  blob_wrapper.to_file('XLSX_WRITER_TEST_DIR', '03_cell_styles.xlsx', xlsx);

end;
/
Source on Github

4. Formulas

A key functionality of Excel is the formulas. XLSX Writer supports formulas, yet, due to a limitation in the xlsx file format, the "calculated" value must be provided with the formula. The following example shows the first values of the fibonacci series:
ex04
declare

  workbook xlsx_writer.book_r;
  sheet        integer;

  xlsx          blob;

  font_courier  integer;
  cs_courier    integer;

  font_bold     integer;
  cs_bold       integer;

  font_italic   integer;
  cs_italic     integer;

  font_underl   integer;
  cs_underl     integer;

begin

  workbook     := xlsx_writer.start_book;
  sheet        := xlsx_writer.add_sheet     (workbook, 'Name of the sheet');


  xlsx_writer.add_cell(workbook, sheet, 1, 1, value_  => 1); 
  xlsx_writer.add_cell(workbook, sheet, 2, 1, value_  => 1); 
  xlsx_writer.add_cell(workbook, sheet, 3, 1, formula => 'SUM(A1:A2)', value_ =>  2); 
  xlsx_writer.add_cell(workbook, sheet, 4, 1, formula => 'SUM(A2:A3)', value_ =>  3); 
  xlsx_writer.add_cell(workbook, sheet, 5, 1, formula => 'SUM(A3:A4)', value_ =>  5); 
  xlsx_writer.add_cell(workbook, sheet, 6, 1, formula => 'SUM(A4:A5)', value_ =>  8); 
  xlsx_writer.add_cell(workbook, sheet, 7, 1, formula => 'SUM(A5:A6)', value_ => 13); 
  xlsx_writer.add_cell(workbook, sheet, 8, 1, formula => 'SUM(A6:A7)', value_ => 21); 

  xlsx     := xlsx_writer.create_xlsx(workbook);

  blob_wrapper.to_file('XLSX_WRITER_TEST_DIR', '04_formulas.xlsx', xlsx);

end;
/
Source on Github

5. Many Columns

This example creates 100 columns. It is used to test if more than 26 columns (names A through Z in Excel) are possible.
ex05
declare

  workbook xlsx_writer.book_r;
  sheet        integer;

  xlsx          blob;

  font_courier  integer;
  cs_courier    integer;

  font_bold     integer;
  cs_bold       integer;

  font_italic   integer;
  cs_italic     integer;

  font_underl   integer;
  cs_underl     integer;

begin

  workbook     := xlsx_writer.start_book;
  sheet        := xlsx_writer.add_sheet     (workbook, 'Name of the sheet');

  for col in 1 .. 100 loop
     xlsx_writer.add_cell(workbook, sheet, 1, col, value_  => col); 
  end loop;

  xlsx     := xlsx_writer.create_xlsx(workbook);

  blob_wrapper.to_file('XLSX_WRITER_TEST_DIR', '05_many_columns.xlsx', xlsx);

end;
/
Source on Github

6. Controls

Excel has also the ability to display controls. Currently, XLSX writer only supports check boxes:
ex06
declare

  workbook xlsx_writer.book_r;
  sheet    integer;

  xlsx     blob;

begin

  workbook := xlsx_writer.start_book;
  sheet    := xlsx_writer.add_sheet  (workbook, 'Name of the sheet');

  xlsx_writer.add_row(workbook, sheet, 2);

  xlsx_writer.col_width(workbook, sheet, 3, 4, 20);

  xlsx_writer.add_checkbox(workbook, sheet, 3, 2, 'Check me');
  xlsx_writer.add_checkbox(workbook, sheet, 4, 2, 'Uncheck me', checked=>true);

  xlsx     := xlsx_writer.create_xlsx(workbook);


  blob_wrapper.to_file('XLSX_WRITER_TEST_DIR', '06_controls.xlsx', xlsx);

end;
/
Source on Github

7. Freezing parts of the sheet

Excel allows to freeze parts of the sheet. This comes in handy if there need to be headers. The following example creates a multiplication sheet and freezes the multiplicators:
ex07
declare

  workbook xlsx_writer.book_r;
  sheet_1  integer;
  sheet_2  integer;
  sheet_3  integer;

  xlsx     blob;

  c_limit   constant integer := 50;
  c_x_split constant integer := 2;
  c_y_split constant integer := 3;

begin

  workbook := xlsx_writer.start_book;
  sheet_1  := xlsx_writer.add_sheet  (workbook, 'Name of sheet one');

  -- { First sheet

  for i in 1 .. c_limit loop
      xlsx_writer.add_cell(workbook, sheet_1,   c_y_split, i+c_x_split, value_ => i);
  end loop;

  for i in 1 .. c_limit loop
      xlsx_writer.add_cell(workbook, sheet_1, i+c_y_split,   c_x_split, value_ => i);
  end loop;

  for x in 1 .. c_limit loop
  for y in 1 .. c_limit loop
      xlsx_writer.add_cell(workbook, sheet_1, c_y_split + x, c_x_split + y, value_ => x*y);
  end loop;
  end loop;

  xlsx_writer.freeze_sheet(workbook, sheet_1, c_x_split, c_y_split);

  -- }
  -- { Second sheet
  sheet_2  := xlsx_writer.add_sheet  (workbook, 'Name of sheet two');

  xlsx_writer.add_cell(workbook, sheet_2, 1, 1, text => 'Foo');
  xlsx_writer.add_cell(workbook, sheet_2, 1, 2, text => 'Bar');
  xlsx_writer.add_cell(workbook, sheet_2, 1, 3, text => 'Baz');

  for r in 1 .. 100 loop
    xlsx_writer.add_cell(workbook, sheet_2, r+1, 1, value_ => r);
    xlsx_writer.add_cell(workbook, sheet_2, r+1, 2, value_ => r*1001);
    xlsx_writer.add_cell(workbook, sheet_2, r+1, 3, value_ => r*10010001);
  end loop;

  xlsx_writer.col_width(workbook, sheet_2, 3, 16);
  xlsx_writer.freeze_sheet(workbook, sheet_2, split_y => 1);

  -- }
  -- { Third sheet
  sheet_3  := xlsx_writer.add_sheet  (workbook, 'Name of sheet three');

  xlsx_writer.add_cell(workbook, sheet_3, 1, 1, text => 'Foo');
  xlsx_writer.add_cell(workbook, sheet_3, 2, 1, text => 'Bar');
  xlsx_writer.add_cell(workbook, sheet_3, 3, 1, text => 'Baz');

  for r in 1 .. 100 loop
    xlsx_writer.add_cell(workbook, sheet_3, 1, r+1, value_ => r);
    xlsx_writer.add_cell(workbook, sheet_3, 2, r+1, value_ => r*1001);
    xlsx_writer.add_cell(workbook, sheet_3, 3, r+1, value_ => r*10010001);
    xlsx_writer.col_width(workbook, sheet_3, r+1, 16);
  end loop;

  xlsx_writer.freeze_sheet(workbook, sheet_3, split_x => 1);

  -- }

  xlsx     := xlsx_writer.create_xlsx(workbook);

  blob_wrapper.to_file('XLSX_WRITER_TEST_DIR', '07_freeze_sheet.xlsx', xlsx);

end;
/
Source on Github